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