很多博客都说RAC好用,但小编发现真正缺少的是如何学习RAC的文章。于是决定自己写一遍关于学习ReactiveCocoa的文章,本文主要针对如何从零开始学习ReactiveCocoa。
如何学习新的框架
- 掌握这个框架常用类,常用方法
- 框架如何设计的,有哪些好的地方
如何导入ReactiveCocoa
Cocoapods是我们的老朋友了。这里我们就使用它。
use_frameworks!
platform :ios, “9.0”
target "RAC练习" do
pod 'ReactiveCocoa', '~> 5.0.0-alpha.5'
end
- 这里注意use_frameworks!不可以少,不然会报错。
ReactiveCocoa常用类:
一、RACSignal
- 能订阅,不能发送
- 只能有一个订阅者
- 多次订阅,则订阅者会多次发送信息
- 只能发送单个值
- 注意:先订阅,再发送
- RACSubscriber订阅者,具备发送消息能力。
- RACDisposable订阅者被销毁时候调用
// 创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@2];
// 如果不再发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// 当订阅者被销毁的时候就会执行
// 信号发送完成或者发送错误,也会执行block,取消订阅信号
NSLog(@"信号被销毁");
}];
}];
// 订阅信号传的值
// 底层:创建订阅者
// 注意:不能分开订阅,要一起订阅
[signal subscribeNext:^(id _Nullable x) {
} error:^(NSError * _Nullable error) {
} completed:^{
}];
二、RACSubject
- 可订阅,可发送
- 可有多个订阅者
- 多次订阅,则订阅者只发送信息一次
- 只能发送单个值
- 注意:先订阅,再发送
// RACSubject语法:
// 创建信号
RACSubject *subject = [RACSubject subject];
// 订阅
// 内部创建RACSubscriber,并且保存起来
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第一个订阅者%@",x);
}];
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"第二个订阅者%@",x);
}];
// 发送信号
// 遍历所有的订阅者,执行nextBlock
[subject sendNext:@1];
- RACSubject使用场景:一个数据需要多个类同时处理-替代代理:
// 类SUNView中代码:
@interface SUNView : UIView
@property (nonatomic, strong) RACSubject *subject;
@end
#import "SUNView.h"
@implementation SUNView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent: (UIEvent *)event{
[_subject sendNext:self];
}
@end
// ViewController中代码:
SUNView *v = [[SUNView alloc] init];
RACSubject *subject = [RACSubject subject];
// 订阅
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"点击了红色%@",x);
}];
v.subject = subject;
[self.view addSubview:v];
三、RACReplaySubject
- 可订阅,可发送
- 只能有一个订阅者
- 可发送多个值
- 注意:无所谓先订阅或先发送
// 创建信号
RACReplaySubject *replaySubject = [RACReplaySubject subject];
// 发送信息
[replaySubject sendNext:@"123"];
[replaySubject sendNext:@"321"];
// 订阅信号
// 遍历值,让一个订阅者去发送多个值
// 只要订阅一次,之前所有发送的值都能获取到.
[replaySubject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
四、RACSequence:RAC中的集合(数组)
- 订阅集合(获取数据)之后,block内的操作,都是在子线程
4.1.OC数组转化为RACSequence,获取信号,订阅。( x 为数组中的单个元素)
NSArray *datas = [NSArray arrayWithContentsOfFile:filePath];
NSMutableArray *arrM = [NSMutableArray array];
// OC数组转化为RAC数组,然后获取信号,然后订阅信号(如果数组中包含的是字典那么,返回的x即为字典,免去遍历数组的代码)
[datas.rac_sequence.signal subscribeNext:^(id _Nullable x) {
FlagItem *item = [FlagItem itemWithDict:x];
[arrM addObject:item];
} completed:^{
}];
4.2.OC字典转化为RACSequence,获取信号,订阅。( x 为单个元组)
NSDictionary *dict = @{@"name" : @"wangsicong", @"money": @100000000};
// 如果是字典那么集合会返回元组RACTuple
[dict.rac_sequence.signal subscribeNext:^(id x) {
//把元祖解析出来
RACTupleUnpack(NSString *key, id value) = x;
}];
//把值包装成元祖
RACTuple *tuple = RACTuplePack(@1, @2, @3);
4.3.OC数组转化为RACSequence,调用map,array函数。( x 为数组中的单个元素)
//使用map函数,直接获取到字典,然后调用RAC的array方法,直接返回数组,比上面代码更加简洁
arrM = [[datas.rac_sequence map:^id _Nullable(id _Nullable value) {
return [FlagItem itemWithDict:value];
}] array];
五、RACMulticastConnection(多路传送连接)
- 为解决 RACSignal被多次订阅,订阅者多次发送信息,而生!
- RAC的弱引用:
@weakify(self)
- RAC的强引用:
@strongify(self)
@weakify(self)
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
@strongify(self);
[self loadData:^(id data) {
[subscriber sendNext:data];
}];
return nil;
}];
//RACSignal转化为RACMulticastConnection,RACMulticastConnection对象中有signal
RACMulticastConnection *connection = [signal publish];
[connection.signal subscribeNext:^(id x) {
}];
[connection.signal subscribeNext:^(id x) {
}];
[connection connect];
六、RACCommand
6.1.RACCommand语法
- RACCommand对象内部必须返回信号
// 创建Command
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
// RACCommand的block
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"你好"];
[subscriber sendCompleted];
return nil;
}];
}];
- execute 触发上面RACCommand的block
// input参数是@1;会返回一个信号
[command execute:@1];
6.2.订阅RACCommand信号
- 用
execute
获取RACCommand对象返回的信号
[[command execute:@1] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
- 用
switchToLatest
获取RACCommand对象返回的信号
// switchToLatest: 获取最近发送的信号
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
-
executionSignals
是信号中的信号,不是对象返回的信号
[command.executionSignals subscribeNext:^(id _Nullable x) {
[x subscribeNext:^(id _Nullable x) {
}];
}];
6.3属性 executing
监听命令是否完成,第一次用skip跳过
[[command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
BOOL isExecuting = [x boolValue];
if (isExecuting) {
NSLog(@"正在执行");
} else {
NSLog(@"执行完成");
}
}];
6.4.RACCommand使用场景:_loginButton.rac_command
第一种Button使用方式:
_loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:input];
return nil;
}];
}];
// 按钮点击监听
[_loginButton.rac_command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
//x即为input
NSLog(@"%@",x);
}];
!第二种Button使用方式:
RACSubject *enableSignal = [RACSubject subject];
_loginButton.rac_command = [[RACCommand alloc] initWithEnabled:enableSignal signalBlock:^RACSignal * _Nonnull(id _Nullable input) {
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:input];
[subscriber sendCompleted];
return nil;
}];
}];
[[_loginButton.rac_command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
BOOL executing = [x boolValue];
//这个信息直接被按钮订阅
[enableSignal sendNext:@(!executing)];
}];