前些内容学习了对一些信号的基本操作,这里将介绍一些如何去创建信号,发送信号以及操作信号
上一篇文章中出现了这样的一句代码:
RACSignal *new_signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"今天是个好日子"];
return [RACDisposable disposableWithBlock:^{
// 处理信号发送结果 (成功或者失败)
//执行完这个bloc,当前信号就被销毁了
}];
//这里也可以直接返回 nil
}];
这里我们简单的创建了一个能发送一串字符的信号,并通过subscriber转为热心号,输入了这个信号。当然,这个信号创建的没有什么意义。在实际应用中,创建信号适用于什么场景呢?
在回到第二篇文字中的登录事件,正常的登录肯定是有网络请求的,当网络请求成功的话,才会会跳转到app的正常界面。那么我们就可以创建一个网络请求的信号,请求成功,发送成功信号。这里借鉴个登录的例子,感谢作者Colin Eberhardt。
- (RACSignal *)loginInSignal{
//创建信号
RACSignal *loginSuccessSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//这里是请求 成功返回YES
BOOL loginSuccess = [self verifyLoginInformationWithUserName:self.nameTextField.text andPassword:self.passwordTextField.text];
//如果登录成功 发送成功信号
[subscriber sendNext:@(loginSuccess)];
}];
// 返回这个信号
return loginSuccessSignal;
}
这样的话,一个登录成功的信号就创建完毕了,我们只需要在点击登录按钮的时候这样做:
[[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
[[self loginInSignal] subscribeNext:^(id x) {
if ([x boolValue]) {
NSLog(@"登录成功");
}
}];
}];
当一个需求的功能越变得复杂,就越体现了RAC的结构的严谨,和代码的简洁。
RACSignal 是RAC里一个比较基本的类,它还有很多信号子类,集成了父类基本的信号功能,同时也有自己的特色。其中有:
RACSubject:
RACSubject 是RACSignal 的 一个子类,通过[RACSubject subject]创建信号。
// 1.创建信号
RACSubject *subject = [RACSubject subject];
// 2.订阅信号
[subject subscribeNext:^(id x) {
NSLog(@"我是第一个订阅者%@",x);
}];
[subject subscribeNext:^(id x) {
NSLog(@"我是第二个订阅者%@",x);
}];
[letters sendNext:@"A"];
[letters sendNext:@"B"];
打印日志:
2016-04-02 00:00:18.090 RACDemo[1511:89968] A
2016-04-02 00:00:18.090 RACDemo[1511:89968] A
2016-04-02 00:00:18.090 RACDemo[1511:89968] B
2016-04-02 00:00:18.091 RACDemo[1511:89968] B
点开源码
- (id)init {
self = [super init];
if (self == nil) return nil;
_disposable = [RACCompoundDisposable compoundDisposable];
_subscribers = [[NSMutableArray alloc] initWithCapacity:1];
return self;
}
可以看到RACSubject类里有一个叫subscribers的可变数组,在初始化的时候创建这个数组,初始容量为1。从subscribe:的实现可以看出,对RACSubject对象的每次subscription,都是将这个subscriber加到subscribers数组中,当发送消息的时候,RACSubject会遍历数组里的订阅者,给每个订阅者发送一个消息。
RACReplaySubject
RACReplaySubject 是 RACSubject的一个子类
RACSignal *sendMessageSinal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"发送消息");
[sendNext:@"10000000"];
return nil;
}];
[sendMessageSinal subscribeNext:^(id x) {
NSLog(@"我是第一个订阅者%@",x);
}];
[sendMessageSinal subscribeNext:^(id x) {
NSLog(@"我是第二个订阅者%@",x);
}];
打印日志:
2016-04-01 23:36:36.493 RACDemo[1215:65403] 发送消息
2016-04-01 23:36:36.494 RACDemo[1215:65403] 我是第一个订阅者,收到消息:10000000
2016-04-01 23:36:36.494 RACDemo[1215:65403] 发送消息
2016-04-01 23:36:36.495 RACDemo[1215:65403] 我是第二个订阅者,收到消息:10000000
可以看到2个订阅者都收到消息的同时,也发送了2次消息,显然,这不是我们想要的。如何保证一个消息被多个订阅者订阅呢:
RACMulticastConnection *connection = [sendMessageSinal multicast:[RACReplaySubject subject]];
[connection connect];
[connection.signal subscribeNext:^(id x) {
NSLog(@"我是第一个订阅者,收到消息:%@",x);
}];
[connection.signal subscribeNext:^(id x) {
NSLog(@"我是第二个订阅者,收到消息:%@",x);
}];
打印日志:
2016-04-01 23:40:26.706 RACDemo[1267:68859] 发送消息
2016-04-01 23:40:26.707 RACDemo[1267:68859] 我是第一个订阅者,收到消息:10000000
2016-04-01 23:40:26.707 RACDemo[1267:68859] 我是第二个订阅者,收到消息:10000000
如此,我们便得到了我们想要的,发送一次消息,被两个接收者收到消息。我们能够明显的感觉到,进行subscription的这个connection.signal 已经不是原来的sendMessageSinal了。事实又是怎样的呢?
点进去,看源码
- (RACMulticastConnection *)multicast:(RACSubject *)subject {
[subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
return connection;
}
- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
NSCParameterAssert(source != nil);
NSCParameterAssert(subject != nil);
self = [super init];
if (self == nil) return nil;
_sourceSignal = source;
_serialDisposable = [[RACSerialDisposable alloc] init];
_signal = subject;
return self;
}
我们可以看到,sendMessageSinal作为信号源被穿进去,但最终返回的却是由[RACReplaySubject subject]而创建出的一个新的信号源。而原来的sendMessageSinal 被保存到sourceSignal里。所以后面的操作都是由connection.signal来配合完成的。
总结: 这里简单分享了一下自己去创建信号和发送信号的步骤以及使用场景,并分析了RACReplaySubject 和 RACSubject这两个信号的作用以及简答实现。