ReactiveCocoa talk about concat and reactivecocoaconcat

Source: Internet
Author: User

ReactiveCocoa talk about concat and reactivecocoaconcat

Today's business process is like this.

1. Get the previous data from CoreData

2. Update the interface

3. Get data from the network

4. Determine the result

5. Handle error judgment

6. Update the interface

7. Determine the numberOfNews Field

8. Real numberOfNews Information

 

The processing of such ordered rows is exactly what ReactiveCocoa is good at solving. Now, how can we use Signal to convert if else into data?

This requires flattenMap and then.

Let's see how React works.

1 // 1. obtain data from CoreData 2 RACSignal * local = [RACSignal createSignal: ^ RACDisposable * (id <RACSubscriber> subscriber) {3/1.1 notify next 4 [subscriber sendNext: nil]; 5 [subscriber sendCompleted]; 6 return nil; 7}]; 8 9 // 2. there is no reason for this process to convert data by performing 10 RACSignal * viewModel = [[local subscribeOn: [RACScheduler schedon] map: ^ id (id value) in mainThread) {11 // 1.2 convert CoreDataModel to view Model 12 return nil; 13}]; 14 15 // 3. display Displayed on the page 16 [viewModel subscribeNext: ^ (id x) {17 18 19}]; 20 21 // 4. create a network request 22 RACSignal * request = [viewModel then: ^ RACSignal * {23 return [RACSignal createSignal: ^ RACDisposable * (id <RACSubscriber> subscriber) {24 25 NSURLSessionTask * task = nil; // create a new network request 26 27 return [RACDisposable disposableWithBlock: ^ {28 if (task. state! = NSURLSessionTaskStateCompleted) {29 [task cancel]; 30} 31}]; 32 33}]; 34 35}]; 36 37 38 39 // 5. avoid repeated requests. Use MutileConnection to convert Signal40 RACMulticastConnection * requestMutilConnection = [request multicast: [RACReplaySubject subject]; 41 [requestMutilConnection connect]; 42 43/6. processing Server result 44 RACSignal * response = [request flattenMap: ^ RACStream * (id value) {45 // For example, response contains an enumerated field of state, determine whether the request is valid. 46 47 // return [RACSignal return: value]; 48 return [RACSignal error: value]; 49}]; 50 51 // 7. update page 52 [response subscribeNext: ^ (id x) {53 // Update page 54 again}]; 55 56 // 8. handle error 57 [response subscribeError: ^ (NSError * error) {58 // handle error 59}];

 

Of course, there is a hole in it to simplify and many logic code is omitted.

Back to the topic, concat is an instance method of RACSignal.

The source code is implemented as follows:

- (RACSignal *)concat:(RACSignal *)signal {return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init];RACDisposable *sourceDisposable = [self subscribeNext:^(id x) {[subscriber sendNext:x];} error:^(NSError *error) {[subscriber sendError:error];} completed:^{RACDisposable *concattedDisposable = [signal subscribe:subscriber];serialDisposable.disposable = concattedDisposable;}];serialDisposable.disposable = sourceDisposable;return serialDisposable;}] setNameWithFormat:@"[%@] -concat: %@", self.name, signal];}

The above code

1. Create a new signal

2. subscribeNext in the original Signal and pass the new Signal subscriber to our concat Signal in the completed block.

It is easy to understand why the next signal can be called when the previous signal is completed, because it is here in signal subscribe: subscriber.

But it's not that simple.

Let's see what happens when you use concat.

A very simple and crude code segment

 1     RACSignal *fristSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 2         3         NSLog(@"oneSignal createSignal"); 4         [subscriber sendNext:@""]; 5         [subscriber sendCompleted]; 6          7         return [RACDisposable disposableWithBlock:^{ 8             NSLog(@"oneSignal dispose"); 9         }];10     }];11     12     RACMulticastConnection *connection = [fristSignal multicast:[RACReplaySubject subject]];13 14     [connection connect];15     16     [connection.signal subscribeNext:^(id x) {17         NSLog(@"2");18     }];19     20     21     RACSignal *afterConcat = [connection.signal concat:[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {22         [subscriber sendNext:@""];23         return nil;24     }]];25     26     [afterConcat subscribeNext:^(id x) {27         NSLog(@"afterConcat subscribeNext");28     }];

Output result

2015-10-15 23:00:26.998 conatAndThen[3814:2388477] oneSignal createSignal2015-10-15 23:00:26.999 conatAndThen[3814:2388477] oneSignal dispose2015-10-15 23:00:27.001 conatAndThen[3814:2388477] 22015-10-15 23:00:27.001 conatAndThen[3814:2388477] afterConcat subscribeNext2015-10-15 23:00:27.002 conatAndThen[3814:2388477] afterConcat subscribeNext

The subscribNext of afterConcat is called twice !!!

Let's see then.

 1     RACSignal *fristSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 2         3         NSLog(@"oneSignal createSignal"); 4         [subscriber sendNext:@""]; 5         [subscriber sendCompleted]; 6          7         return [RACDisposable disposableWithBlock:^{ 8             NSLog(@"oneSignal dispose"); 9         }];10     }];11     12     RACMulticastConnection *connection = [fristSignal multicast:[RACReplaySubject subject]];13 14     [connection connect];15     16     [connection.signal subscribeNext:^(id x) {17         NSLog(@"2");18     }];19     20     21     RACSignal *then = [connection.signal then:^RACSignal *{22         23         return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {24             [subscriber sendNext:@""];25             return nil;26         }];27         28     }];29     30     [then subscribeNext:^(id x) {31         NSLog(@"then subscribNext");32     }];

Output result

2015-10-15 23:02:40.746 conatAndThen[3848:2419019] oneSignal createSignal2015-10-15 23:02:40.747 conatAndThen[3848:2419019] oneSignal dispose2015-10-15 23:02:40.748 conatAndThen[3848:2419019] 22015-10-15 23:02:40.750 conatAndThen[3848:2419019] then subscribNext

This is what we want.

Then is actually packaging concat

Let's see how the source code avoids repeated execution.

- (RACSignal *)then:(RACSignal * (^)(void))block {NSCParameterAssert(block != nil);return [[[selfignoreValues]concat:[RACSignal defer:block]]setNameWithFormat:@"[%@] -then:", self.name];}

The key is in the ignoreValues method.

- (RACSignal *)ignoreValues {return [[self filter:^(id _) {return NO;}] setNameWithFormat:@"[%@] -ignoreValues", self.name];}

To prove my conjecture, filter it once before concat in the demo.

 RACSignal *afterConcat = [[connection.signal filter:^BOOL(id value) {        return NO;    }] concat:[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        [subscriber sendNext:@""];        return nil;    }]];

The result is as follows:

2015-10-15 23:09:51.013 conatAndThen[3967:2511660] oneSignal createSignal2015-10-15 23:09:51.013 conatAndThen[3967:2511660] oneSignal dispose2015-10-15 23:09:51.015 conatAndThen[3967:2511660] 22015-10-15 23:09:51.016 conatAndThen[3967:2511660] afterConcat subscribeNext

More in-depth question: why can I avoid repeated sending when I filter data?

Copy and analyze the source code

RACSignal * after = [RACSignal createSignal: ^ (id <RACSubscriber> subscriber) {RACSerialDisposable * serialDisposable = [[RACSerialDisposable alloc] init]; RACDisposable * sourceDisposable = [connection. signal subscribeNext: ^ (id x) {[subscriber sendNext: x];} error: ^ (NSError * error) {[subscriber sendError: error];} completed: ^ {
RACDisposable * concattedDisposable = [[RACSignal createSignal: ^ RACDisposable * (id <RACSubscriber> subscriber) {[subscriber sendNext: @ "]; // try to add this comment, after subscribeNext only executes return nil;}] subscribe: subscriber]; serialDisposable. disposable = concattedDisposable;}]; serialDisposable. disposable = sourceDisposable; return serialDisposable;}]; [after subscribeNext: ^ (id x) {NSLog (@ "afterConcat subscribeNext");}];

The truth already exists.

The subsciber (A) of the signal (SA) created in the completed block has become the subsciber of the outer Signal, while the connection. the subscribeNext in signal has been on (A) sendNext once, and we need the signal of concat to notify the subscribe once again in SA, so the appearance of then is to avoid [subscriber sendNext: x] Influence on external Execution Process

References

Https://github.com/ReactiveCocoa/ReactiveCocoa

Http://tech.meituan.com/RACSignalSubscription.html

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.