RAC的冷信號和熱信號
本篇目錄
- 何為冷信號,熱信號;
- 為何會有
RACSubject這個類的存在; -
RACSubject已經(jīng)其子類的介紹; - 如何將一個冷信號轉(zhuǎn)成熱信號。
何為冷信號,熱信號?
冷信號:
RAC中的RACSiganl類中幾乎都是冷信號,以+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe方法為例:
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
初始化一個RACDynamicSignal保存一個block,等到有訂閱者去訂閱,如果沒有訂閱者的話,一直不會被調(diào)用,也就是冷信號被調(diào)用的前提是要有訂閱者,這就是冷信號;
熱信號:
解釋完冷信號,那熱信號肯定是即使沒有訂閱者也是會發(fā)送消息的,是的rac提供了RACSubject,專門處理熱信號的。
為何會有RACSubject這個類的存在?
要想解釋為什么會存在RACSubject這個類,首先來一個場景
self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]];
self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
@weakify(self)
RACSignal *fetchData = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
@strongify(self)
NSURLSessionDataTask *task = [self.sessionManager GET:@"fetchData" parameters:@{@"someParameter": @"someValue"} success:^(NSURLSessionDataTask *task, id responseObject) {
[subscriber sendNext:responseObject];
[subscriber sendCompleted];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[subscriber sendError:error];
}];
return [RACDisposable disposableWithBlock:^{
if (task.state != NSURLSessionTaskStateCompleted) {
[task cancel];
}
}];
}];
RACSignal *title = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
if ([value[@"title"] isKindOfClass:[NSString class]]) {
return [RACSignal return:value[@"title"]];
} else {
return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
}
}];
RACSignal *desc = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
if ([value[@"desc"] isKindOfClass:[NSString class]]) {
return [RACSignal return:value[@"desc"]];
} else {
return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
}
}];
RACSignal *renderedDesc = [desc flattenMap:^RACStream *(NSString *value) {
NSError *error = nil;
RenderManager *renderManager = [[RenderManager alloc] init];
NSAttributedString *rendered = [renderManager renderText:value error:&error];
if (error) {
return [RACSignal error:error];
} else {
return [RACSignal return:rendered];
}
}];
RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];
我們再開發(fā)中經(jīng)常會根據(jù)服務(wù)器返回的數(shù)據(jù)解析不同的字段進(jìn)行不同的操作,上面寫的情況在開發(fā)中很常見,如果用Charles抓取的話,其實發(fā)送了3次請求,都知道這個很不好,我們來分析一下為什么會調(diào)用3次呢,我們知道在下面三行代碼執(zhí)行前
RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];
fetchData、title、desc、renderedDesc都是冷信號,當(dāng)調(diào)用上面三行代碼的時候fetchData、title、desc、renderedDesc都變成了熱信號了,而title、desc、renderedDesc信號內(nèi)部都對fetchData信號進(jìn)行了訂閱,從而導(dǎo)致源信號被訂閱了3次,而實際上我們只要發(fā)送一次網(wǎng)絡(luò)請求就可以了,即對源信號只有訂閱一次就夠了。
那我們?nèi)绾巫龅綄υ葱盘栔挥嗛喴淮文兀?code>RACSubject的存在就是解決這個問題的。
RACSubject閃亮登場
借用一下美團(tuán)團(tuán)隊提供的一個例子
RACSubject *subject = [RACSubject subject];
RACSubject *replaySubject = [RACReplaySubject subject];
[[RACScheduler mainThreadScheduler] afterDelay:0.1 schedule:^{
// Subscriber 1
[subject subscribeNext:^(id x) {
NSLog(@"Subscriber 1 get a next value: %@ from subject", x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"Subscriber 1 get a next value: %@ from replay subject", x);
}];
// Subscriber 2
[subject subscribeNext:^(id x) {
NSLog(@"Subscriber 2 get a next value: %@ from subject", x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"Subscriber 2 get a next value: %@ from replay subject", x);
}];
}];
[[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
[subject sendNext:@"send package 1"];
[replaySubject sendNext:@"send package 1"];
}];
[[RACScheduler mainThreadScheduler] afterDelay:1.1 schedule:^{
// Subscriber 3
[subject subscribeNext:^(id x) {
NSLog(@"Subscriber 3 get a next value: %@ from subject", x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"Subscriber 3 get a next value: %@ from replay subject", x);
}];
// Subscriber 4
[subject subscribeNext:^(id x) {
NSLog(@"Subscriber 4 get a next value: %@ from subject", x);
}];
[replaySubject subscribeNext:^(id x) {
NSLog(@"Subscriber 4 get a next value: %@ from replay subject", x);
}];
}];
[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
[subject sendNext:@"send package 2"];
[replaySubject sendNext:@"send package 2"];
}];
輸出
2017-07-03 18:16:02.811 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 1 from subject
2017-07-03 18:16:02.812 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 1 from subject
2017-07-03 18:16:02.812 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 1 from replay subject
2017-07-03 18:16:02.813 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 1 from replay subject
2017-07-03 18:16:02.923 TestObjectProduct[90499:11197356] Subscriber 3 get a next value: send package 1 from replay subject
2017-07-03 18:16:02.923 TestObjectProduct[90499:11197356] Subscriber 4 get a next value: send package 1 from replay subject
2017-07-03 18:16:03.911 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 2 from subject
2017-07-03 18:16:03.911 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 2 from subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 3 get a next value: send package 2 from subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 4 get a next value: send package 2 from subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 2 from replay subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 2 from replay subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 3 get a next value: send package 2 from replay subject
2017-07-03 18:16:03.913 TestObjectProduct[90499:11197356] Subscriber 4 get a next value: send package 2 from replay subject
解釋一下這個結(jié)果
先分別創(chuàng)建兩個信號對象
RACSubject和RACReplaySubject,0.1s分別有兩個訂閱者分別對其訂閱;-
1s后發(fā)送消息,
-
對于
subject有兩個訂閱者
Subscriber 1和Subscriber 2,所以會先給訂閱者發(fā)送消息從而有
-
```
2017-07-03 18:16:02.811 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 1 from subject
2017-07-03 18:16:02.812 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 1 from subject
```
`subject`內(nèi)部有個數(shù)組會保存訂閱者,也就是此時`subject`內(nèi)部已經(jīng)有了2個訂閱者了
2. 對于 `replaySubject`
也有兩個訂閱者`Subscriber 1`和`Subscriber 2`,但是她和`subject`不同,它在訂閱的時候會首先判斷內(nèi)部之前有沒有發(fā)送過值,如果有則發(fā)送給訂閱者
```
2017-07-03 18:16:02.812 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 1 from replay subject
2017-07-03 18:16:02.813 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 1 from replay subject
```
發(fā)完以后,`replaySubject`的內(nèi)部會保存發(fā)送的值,也就是`send package 1`,且有兩個訂閱者。
相信到這里大家沒什么問題
-
1.1s后又多了兩個訂閱者,
Subscriber 3和Subscriber 4;對于
subject,只是保存訂閱者;-
而當(dāng)程序走到下面這行的時候
``` [replaySubject subscribeNext:^(id x) { NSLog(@"Subscriber 3 get a next value: %@ from replay subject", x); }]; ```replaySubject會首先發(fā)送之前保存的值也就是send package 1,從而有了2017-07-03 18:16:02.923 TestObjectProduct[90499:11197356] Subscriber 3 get a next value: send package 1 from replay subject 然后
subject又多了一個訂閱者,保存起來;到這行的時候
```
[replaySubject subscribeNext:^(id x) {
NSLog(@"Subscriber 4 get a next value: %@ from replay subject", x);
}];
```
此時的`replaySubject`有一個值`send package 1`,所以有了
```
2017-07-03 18:16:02.923 TestObjectProduct[90499:11197356] Subscriber 4 get a next value: send package 1 from replay subject
```
- 2s后
subject被訂閱,此時subject的訂閱者有4個從而
```
2017-07-03 18:16:03.911 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 2 from subject
2017-07-03 18:16:03.911 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 2 from subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 3 get a next value: send package 2 from subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 4 get a next value: send package 2 from subject
```
`replaySubject`也有4個訂閱者
```
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 1 get a next value: send package 2 from replay subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 2 get a next value: send package 2 from replay subject
2017-07-03 18:16:03.912 TestObjectProduct[90499:11197356] Subscriber 3 get a next value: send package 2 from replay subject
2017-07-03 18:16:03.913 TestObjectProduct[90499:11197356] Subscriber 4 get a next value: send package 2 from replay subject
```
總結(jié):
-
RACSubject這個類會保存所有的訂閱者,一旦被訂閱,就會保存訂閱者,等待有值發(fā)出的時候,就會告訴所有的訂閱者; -
RACReplaySubject,是繼承RACSubject的所以和RACSubject一樣會保存訂閱者,然后比父類不同的是它還會保存所有發(fā)送過的值,供有新訂閱者訂閱的時候發(fā)送它漏過的值。
如何將一個冷信號轉(zhuǎn)成熱信號。
熱信號一般在開發(fā)中充當(dāng)?shù)慕巧缦聢D所示:

所謂的熱信號就是使用RACSubject對象訂閱源信號,而其他的訂閱者訂閱RACSubject
按照上圖的理解就有下面的例子
- (void)testSubjectMul {
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}];
RACSubject *subject = [RACSubject subject];
[subject subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了");
}];
[subject subscribeNext:^(id x) {
NSLog(@"訂閱者2訂閱了");
}];
[subject subscribeNext:^(id x) {
NSLog(@"訂閱者3訂閱了");
}];
[signal subscribe:subject];
}
輸出
2017-07-04 22:01:14.443 TestObjectProduct[25044:12106160] 源信號被訂閱了
2017-07-04 22:01:14.443 TestObjectProduct[25044:12106160] 訂閱者1訂閱了
2017-07-04 22:01:14.445 TestObjectProduct[25044:12106160] 訂閱者2訂閱了
2017-07-04 22:01:14.445 TestObjectProduct[25044:12106160] 訂閱者3訂閱了
可以看出源信號只被訂閱了一次
- 首先創(chuàng)建源信號;
- 再創(chuàng)建一個RACSubject信號;
- 再對
RACSubject信號進(jìn)行訂閱 - 最后
RACSubject信號對源信號進(jìn)行訂閱。
當(dāng)然RACSubject有提供將冷信號變成熱信號的遍歷方法
- (RACMulticastConnection *)publish;
- (RACMulticastConnection *)multicast:(RACSubject *)subject ;
- (RACSignal *)replay ;
- (RACSignal *)replayLast ;
- (RACSignal *)replayLazily
我們針對上面的demo分別使用一下
- (RACMulticastConnection *)publish
- (RACMulticastConnection *)publish {
RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
RACMulticastConnection *connection = [self multicast:subject];
return connection;
}
這個方法沒有主動connect,一般和- (RACSignal *)autoconnect搭配使用,每當(dāng)autoconnect這個信號訂閱的時候觸發(fā)源信號被訂閱;
- (void)testSubjectMul {
RACSignal *signal = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] publish] autoconnect];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了");
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者2訂閱了");
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者3訂閱了");
}];
}
輸出
2017-07-04 22:08:05.356 TestObjectProduct[25121:12113364] 源信號被訂閱了
2017-07-04 22:08:05.356 TestObjectProduct[25121:12113364] 訂閱者1訂閱了
這里為什么只會有訂閱者1執(zhí)行了,是因為autoconnect只允許connect一次,后面執(zhí)行的只是保存了訂閱者,以便下次執(zhí)行使用。
- (RACMulticastConnection *)multicast:(RACSubject *)subject
- (void)testSubjectMul {
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}];
RACSubject *subject = [RACSubject subject];
RACMulticastConnection *connect = [signal multicast:subject];
[subject subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了");
}];
[subject subscribeNext:^(id x) {
NSLog(@"訂閱者2訂閱了");
}];
[subject subscribeNext:^(id x) {
NSLog(@"訂閱者3訂閱了");
}];
[connect connect];
}
輸出
017-07-04 22:12:26.846 TestObjectProduct[25180:12117807] 源信號被訂閱了
2017-07-04 22:12:26.846 TestObjectProduct[25180:12117807] 訂閱者1訂閱了
2017-07-04 22:12:26.846 TestObjectProduct[25180:12117807] 訂閱者2訂閱了
2017-07-04 22:12:26.846 TestObjectProduct[25180:12117807] 訂閱者3訂閱了
- (RACSignal *)replay
- (void)testSubjectMul {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了");
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者2訂閱了");
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者3訂閱了");
}];
}
輸出
2017-07-04 22:14:22.805 TestObjectProduct[25224:12120354] 源信號被訂閱了
2017-07-04 22:14:22.805 TestObjectProduct[25224:12120354] 訂閱者1訂閱了
2017-07-04 22:14:22.806 TestObjectProduct[25224:12120354] 訂閱者2訂閱了
2017-07-04 22:14:22.806 TestObjectProduct[25224:12120354] 訂閱者3訂閱了
這個一調(diào)用replay的時候就對源信號訂閱了,只不過當(dāng)時沒有訂閱者,由于內(nèi)部使用的是RACReplaySubject對象,此時會保存發(fā)送的值,等到訂閱者訂閱的時候就會發(fā)送保存的值了
比如稍微改一下
- (void)testSubjectMul {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] replay];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了");
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者2訂閱了");
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者3訂閱了");
}];
}
就會輸出
2017-07-04 22:17:06.612 TestObjectProduct[25277:12124611] 源信號被訂閱了
2017-07-04 22:17:06.613 TestObjectProduct[25277:12124611] 訂閱者1訂閱了
2017-07-04 22:17:06.613 TestObjectProduct[25277:12124611] 訂閱者1訂閱了
2017-07-04 22:17:06.613 TestObjectProduct[25277:12124611] 訂閱者2訂閱了
2017-07-04 22:17:06.613 TestObjectProduct[25277:12124611] 訂閱者2訂閱了
2017-07-04 22:17:06.614 TestObjectProduct[25277:12124611] 訂閱者3訂閱了
2017-07-04 22:17:06.614 TestObjectProduct[25277:12124611] 訂閱者3訂閱了
- (RACSignal *)replayLast
- (void)testSubjectMul {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendNext:@"假設(shè)這是另一個網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] replayLast];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了--%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者2訂閱了--%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者3訂閱了--%@",x);
}];
}
輸出
2017-07-04 22:19:52.137 TestObjectProduct[25395:12129467] 源信號被訂閱了
2017-07-04 22:19:52.138 TestObjectProduct[25395:12129467] 訂閱者1訂閱了--假設(shè)這是另一個網(wǎng)絡(luò)
2017-07-04 22:19:52.138 TestObjectProduct[25395:12129467] 訂閱者2訂閱了--假設(shè)這是另一個網(wǎng)絡(luò)
2017-07-04 22:19:52.138 TestObjectProduct[25395:12129467] 訂閱者3訂閱了--假設(shè)這是另一個網(wǎng)絡(luò)
這個和replay類似,唯一的不同就是replay保存所以發(fā)送過的值,而它保存的是最新的發(fā)送的值
- (RACSignal *)replayLazily
這個要和replay對比看,replay方法是即使沒有訂閱者,源信號也會被訂閱,而replayLazily只有當(dāng)返回的信號被訂閱的時候源信號才會被訂閱,先看replay
- (void)testSubjectMul {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendNext:@"假設(shè)這是另一個網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] replay];
輸出
2017-07-04 22:24:02.298 TestObjectProduct[25558:12136590] 源信號被訂閱了
再看replayLazily,先看她沒有被訂閱
- (void)testSubjectMul {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendNext:@"假設(shè)這是另一個網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] replayLazily];
}
輸出
無
再看被訂閱了
- (void)testSubjectMul {
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"源信號被訂閱了");
[subscriber sendNext:@"假設(shè)這是網(wǎng)絡(luò)"];
[subscriber sendNext:@"假設(shè)這是另一個網(wǎng)絡(luò)"];
[subscriber sendCompleted];
return nil;
}] replayLazily];
[signal subscribeNext:^(id x) {
NSLog(@"訂閱者1訂閱了--%@",x);
}];
}
輸出
2017-07-04 22:26:56.527 TestObjectProduct[25601:12139422] 源信號被訂閱了
2017-07-04 22:26:56.528 TestObjectProduct[25601:12139422] 訂閱者1訂閱了--假設(shè)這是網(wǎng)絡(luò)
2017-07-04 22:26:56.528 TestObjectProduct[25601:12139422] 訂閱者1訂閱了--假設(shè)這是另一個網(wǎng)絡(luò)
說道這里我們可以修改一下開始那個網(wǎng)絡(luò)請求了
self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]];
self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
@weakify(self)
RACSignal *fetchData = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
@strongify(self)
NSURLSessionDataTask *task = [self.sessionManager GET:@"fetchData" parameters:@{@"someParameter": @"someValue"} success:^(NSURLSessionDataTask *task, id responseObject) {
[subscriber sendNext:responseObject];
[subscriber sendCompleted];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[subscriber sendError:error];
}];
return [RACDisposable disposableWithBlock:^{
if (task.state != NSURLSessionTaskStateCompleted) {
[task cancel];
}
}];
}] replayLazily];//只要加一個這個就可以了
RACSignal *title = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
if ([value[@"title"] isKindOfClass:[NSString class]]) {
return [RACSignal return:value[@"title"]];
} else {
return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
}
}];
RACSignal *desc = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
if ([value[@"desc"] isKindOfClass:[NSString class]]) {
return [RACSignal return:value[@"desc"]];
} else {
return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
}
}];
RACSignal *renderedDesc = [desc flattenMap:^RACStream *(NSString *value) {
NSError *error = nil;
RenderManager *renderManager = [[RenderManager alloc] init];
NSAttributedString *rendered = [renderManager renderText:value error:&error];
if (error) {
return [RACSignal error:error];
} else {
return [RACSignal return:rendered];
}
}];
RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];