入职有一段时间了,没有开发任务,白天就看看博客写写自己的东西,晚上看世界杯,简直不要太爽,就是天台有点挤了(╯3╰)。
最近在学习ReactiveCocoa,项目导入ReactiveObjC开干。
RACSignal
RACSignal是RAC核心的类,使用的时候先创建信号,订阅信号,在创建信号的block里面发送信号。
- (void)RACSignal
{
//1 创建信号
RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
//3 发送信号
[subscriber sendNext:@"发送信号"];
return [RACDisposable disposableWithBlock:^{
NSLog(@"取消订阅");
}];
// return nil;
}];
//2 订阅信号
RACDisposable * disposable = [signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//4 取消订阅
[disposable dispose];
}
RACSubject
RACSubject是继承自RACSignal,同时也遵循RACSubscriber协议。所以RACSubject既可以订阅信号,也能发送信号。使用方法也是先订阅后发送。它和RACReplaySubject的区别是,RACReplaySubject可以先发送后订阅。
- (void)RACSubject
{
//1 创建信号
RACSubject * subject = [RACSubject subject];
//2 订阅信号
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//3 发送信号
[subject sendNext:@"发送信号"];
}
RACSequence
RACSequence一般用于遍历数组和字典等容器类,RAC扩展了一种数据类型Tuple元祖,接触过Swift的一定不会陌生。
- (void)RACSequence
{
//遍历
NSArray * array = @[@"1",@"2",@"3",@"3",@"5"];
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//元祖
RACTuple * tuple = RACTuplePack(array);
NSLog(@"%@",tuple[0]);
NSLog(@"%@",[tuple first]);
NSLog(@"%@",[tuple last]);
NSDictionary * dict = @{@"key1":@"value1",@"key2":@"value2"};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
RACTupleUnpack(NSString * key,NSString * value) = x;
NSLog(@"%@ %@",key,value);
}];
//替换数组的元素 生成新的数组 单个操作
NSArray * newArray1 = [[array.rac_sequence map:^id _Nullable(id _Nullable value) {
return @"0";
}] array];
NSLog(@"%@",newArray1);
//替换数组的元素 生成新的数组 全部操作
NSArray * newArray2 = [[array.rac_sequence mapReplace:@"1"] array];
NSLog(@"%@",newArray2);
}
RACMulticastConnection
ReactiveCocoa中信号默认都是冷的,每次有新的订阅者订阅信号的时候都会执行信号创建时传入的block。举个例子,把一个网络请求的结果设置为信号,多个UI订阅了这个信号,每次订阅的时候,都会进行一次网络请求。
RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
/*网络请求*/
[subscriber sendNext:@"发送信号"];
return nil;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
为了避免这一情况,使用RACMulticastConnection,创建链接类,将订阅者连接起来,把信号源变成热信号。
- (void)RACMulticastConnection
{
//多个订阅者 只发一个信号
RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
[subscriber sendNext:@"发送信号"];
return nil;
}];
//创建链接类
RACMulticastConnection * connection = [signal publish];
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//连接 把信号源变为热信号
[connection connect];
}
merge
信号的合并
- (void)merge
{
RACSubject * subject1 = [RACSubject subject];
RACSubject * subject2 = [RACSubject subject];
RACSubject * subject3 = [RACSubject subject];
[[RACSignal merge:@[subject1,subject2,subject3]] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject1 sendNext:@"subject1"];
[subject2 sendNext:@"subject2"];
[subject3 sendNext:@"subject3"];
}
group
类似于GCD的任务组,完成多个任务后才能执行某个方法
- (void)group
{
RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
/*网络请求1*/
[subscriber sendNext:@"请求1完成"];
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
/*网络请求2*/
[subscriber sendNext:@"请求2完成"];
return nil;
}];
[self rac_liftSelector:@selector(dependSignalA:WithSignalB:) withSignalsFromArray:@[signalA,signalB]];
}
- (void)dependSignalA:(NSString *)str1 WithSignalB:(NSString *)str2
{
}
Notification && KVO
RAC来替换Notification和KVO的
- (void)Notification
{
//不用写removeObserver
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"NotificationName" object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"%@",x);
}];
}
- (void)KVO
{
[[self.view rac_valuesForKeyPath:@"color" observer:self] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}
Timer
RAC实现一个Timer的功能
- (void)Timer
{
RACDisposable * disposable = [[RACSignal interval:1.f onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
//当前时间
NSLog(@"%@",x);
[disposable dispose];
}];
}
UI
再来看看RAC在UI上的一些应用
- (void)UI
{
UITextField * tf = [UITextField new];
UITextField * tf2 = [UITextField new];
UIButton * btn = [UIButton new];
[[tf rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
//filter 和 ignore
[[[tf2.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
return value.length > 6;
}] ignore:@"666"] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
//响应事件
[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"%@",x);
}];
//两个输入框长度大于3的时候 按钮才可以点击
RAC(btn,enabled) = [RACSignal combineLatest:@[tf.rac_textSignal,tf2.rac_textSignal] reduce:^id (NSString * str1, NSString * str2){
return @(str1.length > 3 && str2.length > 3);
}];
}
ReactiveCocoa是个响应式编程框架,在iOS中没有接触过类似的代码。不过之前有接触过AngularJS,对里面ng-Model指令,单向绑定、双向绑定有一定的了解。下篇会重点理解RACCommand,结合一个登录的Demo来实践。
代码: ReactiveObjCDemo