整理了开发中一些特定场景下使用 RAC 的便利之处,关于一些常用的 API 的使用网上的资源还是很多的,就不做举例了。
- 比如登录页面当用户输入的账号、密码长度合法的情况下才可以点击登录按钮,否则按钮不可点击,这里条件比较简单,即账号密码长度都大于5,其实还可以使用一些正则匹配账号格式是否正确等。combineLatest 就是合并多个信号,且每个信号至少发送过一次 sendNext,才会触发合并信号。
1 2 3
| RAC(self.loginBT, enabled) = [RACSignal combineLatest:@[self.accountTF.rac_textSignal, self.passWordTF.rac_textSignal] reduce:^(NSString *usernameValid, NSString *passwordValid) { return @(usernameValid.length > 5 && passwordValid.length > 5); }];
|
- 使用 RACSubject 替代 Delegate,每调用一次 test 方法,则对应在 toVC2 方法中打印一次接受的 value 值。 这里利用的就是 RACSubject 既可以创建信号又可以发送信号的特性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @interface TestVC1 : UIViewController
@end
@implementation TestVC1
-(void)toVC2:(UIButton *)btn { TestVC2 *VC2 = [[TestVC2 alloc] init]; [VC2.subject subscribeNext:^(NSString *value) { NSLog(@"value = %@", value); }]; [self.navigationController pushViewController:VC2 animated:YES] }
@end
@interface TestVC2 : UIViewController
@property (nonatomic, strong) RACSubject *shareSubject;
@end
@implementation TestVC2
-(void)test:(UIButton *)btn { [self.subject sendNext(@"test")]; }
-(RACSubject*)subject { if (!_subject) { _subject = [RACSubject subject]; } return _subject; } @end
|
- RACScheduler 计时器,这里看源码的话,可以看到最终是对 GCD 计时器的封装,当然也可以实现倒计时。
1 2 3 4 5 6 7 8 9 10 11 12 13
| - (void)start { __block NSUInteger timerNum = 0; self.disposable = [[RACScheduler mainThreadScheduler] after:[NSDate date] repeatingEvery:1.f withLeeway:0 schedule:^{ self.controlView.timerNum = timerNum; timerNum++; }]; }
-(void)stop { [self.disposable dispose]; }
|
- 在控制器的 viewDidDisappear、dealloc 或者其他一些方法中执行某些操作。这个方法就是当监听到 self 的 viewDidDisappear 方法执行后会发送信号,然后做一些处理。某些方面讲这并不是一个好例子,这里也仅仅是对 rac_signalForSelector 使用的一个说明,就是通过此 API 可以监听某对象的在执行特定消息时可以回调给开发者。
1 2 3 4 5 6
| -(void)addObserve { [[self rac_signalForSelector:@selector(viewDidDisappear:)] subscribeNext:^(id x) { [MBProgressHUD hideHUD]; }]; }
|
- 使用 RACCommand 执行网络请求,这里在实际开发中,需要对 response、error 进行判断。可以看到其实 RACCommand 内部封装的是一个信号,每当执行 RACCommand 时就会创建一个信号,所以一个 RACCommand 里包含了多个信号,如果想获取最新的信号,需要使用 executionSignals.switchToLatest,而执行一个 RACCommand 也很简单,调用 execute 即可,当然还可以传递参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| -(void)initialize { [self.loadDataCommand.executionSignals.switchToLatest subscribeNext:^(id response) { @strongify(self) NSLog(@"response = %@", response); }]; }
-(RACCommand *)loadDataCommand { if (!_loadDataCommand) { _loadDataCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [[BHNetReqManager sharedManager].bh_requestUrl(kNmpaiFound) startRequestWithCompleteHandler:^(NSURLSessionDataTask *task, id response, NSError *error) { @strongify(self) [subscriber sendNext:response]; [subscriber sendCompleted]; }]; return nil; }]; }];
} return _loadDataCommand; }
|
- 为网络失败添加重试机制,当然重试机制的使用场景还是很多的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| __block int failedCount = 0;
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) { if (failedCount < 9) { failedCount++; NSLog(@"我失败了"); [[BHNetReqManager sharedManager].bh_requestUrl(@"http://binhan1029.github.io/") startRequestWithCompleteHandler:^(id response, NSError *error) { [subscriber sendError:nil]; }]; } else { [subscriber sendNext:@"成功"]; } return nil; }]; RACSignal *retrySignal = [signal retry]; [retrySignal subscribeNext:^(id x) { NSLog(@"终于成功了"); }];
|
相关资料:
http://tech.meituan.com/potential-memory-leak-in-reactivecocoa.html?from=timeline&isappinstalled=0