IOS responsive programming framework ReactiveCocoa (RAC) example, iosreactivecocoa
ReactiveCocoa is an implementation framework of responsive programming (FRP) in IOS, its open source address is: https://github.com/ReactiveCocoa/ReactiveCocoa#; read several articles on the internet, I feel a lot of theory, but the code is still not quite understandable, so I have implemented some of the classic examples used in its github document. You can directly use them when necessary in the project, it is easier to understand the source code.
Example 1: Listen for changes in the member variables of the object. When the value of the member variables is changed, some things are triggered.
This is actually the scenario used by the ios kvo mechanism. The KVO implementation usually involves three steps: 1. Add a listener to the member variables of the object; 2. Implement listener callback; 3, with RAC, you can directly cancel listening. RAC callback is implemented through block. Similar to procedural programming, the context is easier to understand.
Scenario: The current class has a member variable NSString * input. When its value is changed, a request is sent.
Implementation:
[RACObserve (self, input) subscribeNext: ^ (NSString * x) {request (x); // send a request}];
Each time the input value is modified, the block is called and the modified value is passed as a parameter.
Scenario: in the preceding scenario, a request is sent only when the input value starts with 2.
Implementation:
[[RACObserve (self, input) filter: ^ (NSString * value) {if ([value hasPrefix: @ "2"]) {return YES ;} else {return NO ;}] subscribeNext: ^ (NSString * x) {request (x); // send a request}];
Scenario: the above scenario is to listen to your own member variables. If you want to listen for changes in UITextField input values, the framework is encapsulated to replace the system callback.
Implementation:
[[Self. priceInput. rac_textSignal filter: ^ (NSString * str) {if (str. integerValue> 20) {return YES;} else {return NO ;}] subscribeNext: ^ (NSString * str) {<span style = "white-space: pre "> </span> request (x); // send a request}];
Example 2. Listen for multiple variable changes at the same time. When these variables meet certain conditions, make the button clickable status.
Scenario: the button listens to two input boxes with a value and a member variable value. When the input box has an input and the member variable is true, the button is clickable.
Implementation:
RAC(self.payButton,enabled) = [RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && [connect boolValue]); }];
Scenario: send a request directly when the preceding conditions are met
Implementation:
[[RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && ![connect boolValue]); }] subscribeNext:^(NSNumber *res){ if ([res boolValue]) { NSLog(@"XXXXX send request"); } }];
Example 3. production-consumption
Scenario: each time a user enters a character in TextField, a request is sent if there is no other input within one second. The trigger event of character change in TextField is displayed in Example 1. Here we implement the method of its touch, and implement the 1 second delay in this method.
Implementation:
-(Void) showLoading {[self. loadingDispose dispose]; // the last signal has not been processed. Cancel it (less than 1 second since the last generation) @ weakify (self); self. loadingDispose = [[RACSignal createSignal: ^ RACDisposable * (id <RACSubscriber> subscriber) {[subscriber sendCompleted]; return nil;}] delay: 1] // subscribeCompleted with one second of latency: ^ {@ strongify (self); doRequest (); self. loadingDispose = nil;}];}
The above Code seems confusing, but the following code is easier to understand:
[self.loadingDispose dispose]; RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {//BLOCK_1 subscriptions++; [subscriber sendNext:@"mytest"]; [subscriber sendCompleted]; return nil; }]; loggingSignal = [loggingSignal delay:10]; self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){//BLOCK_2 NSLog(@"%@",x); NSLog(@"subscription %u", subscriptions); }]; self.loadingDispose = [loggingSignal subscribeCompleted:^{//BLOCK_3 NSLog(@"subscription %u", subscriptions); }];
LoggingSignal is triggered every time the subscriibeNext: ^ (id x) or subscribeCompleted: ^ method is called (12 rows and 17 rows). When it creates the input parameter block_1, the sendNext: Method in block_1 calls the corresponding block_2 in subscriibeNext: ^, while sendCompleted in block_1 calls the corresponding block_3 in subscribeCompleted: