RAC
指的就是RactiveCocoa
,是Github
的一個開源框架,能夠幫我們提供大量方便的事件處理方案,讓我們更簡單粗暴地去處理事件,現在分為ReactiveObjC
和ReactiveSwift
,兩個框架的功能使用相似,由于正好在學習這個然后公司項目是用OC
寫的,所以將ReactiveObjC
的使用方法記錄一下。
ReactiveObjC 的使用
RAC
的核心思想:創建信號
- 訂閱信號
- 發送信號
,并且在 RAC
中我們會看到大量的 block
,所以在使用之前可以再重新溫習一下 block
的使用。
1. RACSignal 信號
/* 創建信號 */
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
/* 發送信號 */
[subscriber sendNext:@"發送信號"];
return nil;
}];
/* 訂閱信號 */
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"信號內容:%@", x);
}];
/* 取消訂閱 */
[disposable dispose];
2. RACSubject 信號
和代理的用法類似,通常用來代替代理,有了它,就不必要定義代理了。
/* 創建信號 */
RACSubject *subject = [RACSubject subject];
/* 發送信號 */
[subject sendNext:@"發送信號"];
/* 訂閱信號(通常在別的視圖控制器中訂閱,與代理的用法類似) */
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"信號內容:%@", x);
}];
3. RACTuple 元祖
RAC
的元祖,跟我們 OC
的數組其實是一樣的,它其實就是封裝了我們 OC
的數組。
/* 創建元祖 */
RACTuple *tuple = [RACTuple tupleWithObjects:@"1", @"2", @"3", @"4", @"5", nil];
/* 從別的數組中獲取內容 */
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"1", @"2", @"3", @"4", @"5"]];
/* 利用 RAC 宏快速封裝 */
RACTuple *tuple = RACTuplePack(@"1", @"2", @"3", @"4", @"5");
NSLog(@"取元祖內容:%@", tuple[0]);
NSLog(@"第一個元素:%@", [tuple first]);
NSLog(@"最后一個元素:%@", [tuple last]);
4. 便利 Array 數組和 Dictionary 字典
可以省去使用 for
循環來遍歷。
/* 遍歷數組 */
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"數組內容:%@", x); // x 可以是任何對象
}];
/* 遍歷字典 */
NSDictionary *dictionary = @{@"key1":@"value1", @"key2":@"value2", @"key3":@"value3"};
[dictionary.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) {
RACTupleUnpack(NSString *key, NSString *value) = x; // x 是一個元祖,這個宏能夠將 key 和 value 拆開
NSLog(@"字典內容:%@:%@", key, value);
}];
下面兩個方法都是將數組內容全部換為 0
,第一個是單個操作,,第二個是一次性全部替換,兩個方法都不會改變原數組內容,操作完后都會生成一個新的數組,省去了創建可變數組然后遍歷出來單個添加的步驟。
/* 內容操作 */
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
NSArray *newArray = [[array.rac_sequence map:^id _Nullable(id _Nullable value) {
NSLog(@"數組內容:%@", value);
return @"0"; // 將所有內容替換為 0
}] array];
/* 內容快速替換 */
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"];
NSArray *newArray = [[array.rac_sequence mapReplace:@"0"] array]; // 將所有內容替換為 0
5. 監聽 TextField 的輸入改變
可以省去設置 delegate
和實現代理方法的步驟。
/* 監聽 TextField 的輸入(內容改變就會調用) */
[[textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"輸入框內容:%@", x);
}];
/* 添加監聽條件 */
[[textField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
return value.length > 5; // 表示輸入文字長度 > 5 時才會調用下面的 block
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"輸入框內容:%@", x);
}];
6. 監聽 Button 點擊事件
可以省去 addTarget
添加事件和創建方法的步驟。
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"%@ 按鈕被點擊了", x); // x 是 button 按鈕對象
}];
7. 登錄按鈕狀態實時監聽
下面表示只有 用戶名
和 密碼
輸入框內容都大于 0
時,登錄
按鈕才可以點擊,而且狀態是實時監聽的,一句代碼就能完成這個功能。
RAC(_loginButton, enabled) = [RACSignal combineLatest:@[_username.rac_textSignal, _password.rac_textSignal] reduce:^id _Nullable(NSString * username, NSString * password){
return @(username.length && password.length);
}];
8. 監聽 Notification 通知事件
可省去在 -(void)dealloc {}
中清除通知和監聽通知創建方法的步驟。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"%@ 鍵盤彈起", x); // x 是通知對象
}];
9. 代替 Delegate 代理方法
可以省去監聽以及設置 delegate
的步驟,下面表示只要 view
中執行了 btnClick
這個方法,就會發送信號執行這個回調。
[[view rac_signalForSelector:@selector(btnClick)] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@" view 中的按鈕被點擊了");
}];
10. 代替 KVO 監聽
可以代替 KVO
監聽,下面表示把監聽 view
的 frame
屬性改變轉換成信號,只要值改變就會發送信號。
[[view rac_valuesForKeyPath:@"frame" observer:self] subscribeNext:^(id _Nullable x) {
NSLog(@"屬性的改變:%@", x); // x 是監聽屬性的改變結果
}];
還有一種更簡單的寫法,就是利用 RAC
的宏,和上面的效果是一樣的。
[RACObserve(view, frame) subscribeNext:^(id _Nullable x) {
NSLog(@"屬性的改變:%@", x); // x 是監聽屬性的改變結果
}];
11. 代替 NSTimer 計時器
可以代替 NSTimer
使用。
@interface ViewController ()
@property (nonatomic, strong) RACDisposable *disposable;
@end
/* 定義計時器監聽 */
self.disposable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"當前時間:%@", x); // x 是當前的系統時間
/* 關閉計時器 */
[_disposable dispose];
}];
持續更新,學習到新的知識在記錄下來,有需要的可以收藏一下。
將來的你,一定會感激現在拼命的自己,愿自己與讀者的開發之路無限美好。