ReactiveCocoa(RAC) is a new framework for iOS and OS X development that is open source on GitHub. RAC features functional programming and responder programming.
Problems solved by ReactiveCocoa:
- 1. The problem of too much dependence between states and states in traditional iOS development process
- 2. Problems of traditional MVC architecture :Controller is complicated and has poor testability
- 3. Provide a unified messaging mechanism
1. Key value observation – Listen for changes in TF values
- (void)demo1{ @weakify(self); [self.tF.rac_textSignal subscribeNext:^(NSString *value) { @strongify(self); self.value = value; }]; // Call Block when self.value changes, using KVO mechanism, KVO [RACObserve(self, value) subscribeNext:^(NSString *value) {NSLog(@"%@",value);}]; }Copy the code
2. The use of the map
- (void)demo2{RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // This signal has a Next event and a complete event [subscriber sendNext:@" sing "]; [subscriber sendCompleted]; return nil;}]; // Improve the signal when the signal is singing. Return self.value RAC(self, Tf.text) = [signalA map:^id(NSString *value) {if ([value isEqualToString:@" sing "]) {return @" dance ";} return @"";}]; }Copy the code
If you go west, he goes east; if he goes left, you go right
RACChannelTerminal *channelA = RACChannelTo(self, value); - (void)demo3{// Create A RACChannelTerminal * channelterminal = RACChannelTo(self, value); RACChannelTerminal *channelB = RACChannelTo(self, value2); [[channelA map:^id(NSString *value) {if ([value isEqualToString:@" west "]) {NSLog(@" east "); Return @ "east";} NSLog (@ "= = = = = = % @", value); the return value;}] the subscribe: channelB]; [channelB map:^id(id value) {if ([value isEqualToString:@" left "]) {channelB map:^id(id value) {if ([value isEqualToString:@" left "]) {channelB map:^id(id value) { NSLog (@ "right"); return @ "right";} NSLog (@ "= = = = = = % @", value); the return value;}] the subscribe: channelA]; // Channel B flows to channel A //KVO monitors the change of valueA, filters valueA, and returns Yes. Value) filter:^BOOL(id value) {return value? YES: NO;}] subscribeNext:^(id x) {NSLog(@" u ",x);}]; [[RACObserve(self, value2) filter:^BOOL(id value) {return value? YES: NO;}] subscribeNext: ^ (id) x {NSLog (@ "he told the % @", x);}]; Self. value = @" west "; self.value = @" west "; Self. value2 = @" left "; }Copy the code
4. The agent
1) The first way of writing agent
.m files
- (void)demo4{self.delegate makeAnApp:@"12345 "String:@" 1245 "]; }Copy the code
.h files
- (void)makeAnApp:(NSString *)string String:(NSString *)string;
@end
@interface Base5Controller : UIViewController
@property (nonatomic, assign)id<ProgrammerDelegate> delegate;
Copy the code
Dot h for the first controller
Base5Controller *base = [[Base5Controller alloc] init]; // base.delegate = self; [self demo4]; // This is a pit, the proxy must be set up last, otherwise the signal can not be subscribed // Lei Explained: when setting up the proxy, Base. Delegate = self; Base. Delegate = self; base. [self.navigationController pushViewController:base animated:YES]; } else { [self.navigationController pushViewController:[cl new] animated:YES]; }} #pragma mark-- rac_signalForSelector: FromProtocol: this method replaces the proxy by setting self to the proxy at the end of the subscription proxy signal, otherwise it will not execute - (void)demo4{ // Add a signal to self representing the makeAnApp of the ProgrammerDelegate agent; //RACTuple equals the primitive in Swift [[self rac_signalForSelector:@selector(makeAnApp:String:) FromProtocol :@protocol(ProgrammerDelegate)] subscribeNext:^(RACTuple *x) {// Here you can immediately execute the code NSLog for the makeAnApp method ",x.first); NSLog(@"%@",x.second); }]; }Copy the code
2) Method 2 uses RACSubject instead of proxy
/** * RACSubject: signal provider, can act as a signal, can send a signal. Create RACSubject 2. subscribe signal 3. send signal workflow: 1. Subscribe signal, internally save the subscriber, and the subscriber corresponding block 2. When sending the signal, traverse the subscriber, call the subscriber's nextBolck note: if subscribe signal, must subscribe before sending the signal, otherwise receive no signal, there is a difference between using RACReplaySubject */ -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ RacSubjectController *racsub = [[RacSubjectController alloc] init]; racsub.subject = [RACSubject subject]; [racsub.subject subscribeNext:^(id x) {NSLog(@" notified %@",x);}]; [self.navigationController pushViewController:racsub animated:YES]; }Copy the code
Declare properties in racSubjectController.h
@property (nonatomic, strong) RACSubject *subject;
Copy the code
.m for data transfer
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ if (self.subject) { [self.subject sendNext:@1]; }}Copy the code
Radio 5.
// Send notification - (void)demo5{NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; // Send broadcast notification [Center postNotificationName:@" woman's friend "object:nil userInfo:@{@" tip ":@" listen "}]; } // Receive notification NSNotificationCenter * Center = [NSNotificationCenter defaultCenter]; RACSignal *siganl = [center rac_addObserverForName:@" woman's Friend "object:nil]; [siganl subscribeNext:^(NSNotification *x) {NSLog(@" tip: %@", x.userinfo [@" tip "]));}];Copy the code
6. Two signals in series, two tubes in series, one tube finished processing their own things, the next tube began to process their own things
- (void)demo6{// Create A RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@" eat "]; [subscriber sendCompleted]; return nil;}]; RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber [subscriber sendCompleted]; return nil;}]; [subscriber sendCompleted];}]; RACSignal *concatSiganl = [siganlA concat:siganlB]; [concatSiganl subscribeNext:^(id x) {NSLog(@"%@",x);}]; }Copy the code
7. Parallel connection, as long as there is something in a tube, you can print
- (void)demo7{// create A RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@" paper factory sewage "]; [subscriber sendCompleted]; return nil;}]; RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber SendNext :@" electroplating plant sewage "]; [subscriber sendCompleted]; return nil;}]; RACSignal mergeSiganl = [RACSignal merge:@[siganlA,siganlB]]; [mergeSiganl subscribeNext:^(id x) { NSLog(@"%@",x); }]; }Copy the code
8. Combination, only two signals have values, can be combined
- (void)demo8{RACSubject *letters = [RACSubject subject]; RACSubject *numbers = [RACSubject subject]; // [RACSignal combineLatest:@[letters,numbers] reduce:^(NSString *letter, NSString *number){ return [letter stringByAppendingString:number]; }] subscribeNext:^(id x) { NSLog(@"%@",x); }]; [letters sendNext:@"A"]; [letters sendNext:@"B"]; [numbers sendNext:@"1"]; // print B1 [letters sendNext:@"C"]; // print C1 [numbers sendNext:@"2"]; // print C2}Copy the code
9. Confluence compression
- (void)demo9{// create A RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@" red "]; [subscriber sendCompleted]; return nil;}]; RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber SendNext :@" white "]; [subscriber sendCompleted]; return nil;}]; [siganlA zipWith:siganlB] subscribeNext:^(id x) {RACTupleUnpack(NSString *stringA, NSString *stringB) = x; NSLog(@"%@ %@",stringA, stringB); }]; }Copy the code
Mapping, I can turn everything into gold
- (void)demo10{ RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:nil]; [subscriber sendCompleted]; return nil; }]; Siganl = [siganl map: id(NSString *value) {if ([value isEqualToString:@" iD "]) {return @" iD "; } return value; }]; // Print, no matter what signal is sent, this step is done. }Copy the code
11. Filtering. Under 18 years old, no entry
- (void)demo11{ RACSignal *singal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@(15)]; [subscriber sendNext:@(17)]; [subscriber sendNext:@(21)]; [subscriber sendNext:@(14)]; [subscriber sendNext:@(30)]; [subscriber sendCompleted]; return nil; }]; [[singal filter:^BOOL(NSNumber *value) {return value. IntegerValue >= 18; / / return to yes can}] subscribeNext: ^ (id) x {NSLog (@ "% @", x);}]; }Copy the code
12. A mathematical map method (a flattener can also be replaced with a then method that does the same thing)
-(void)demo12{ RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@" egg-beating "); [subscriber sendNext:@" egg-beating "]; [subscriber sendCompleted]; return nil;}]; NSLog(@" egg-beating "); [subscriber sendCompleted]; return nil;}]; Siganl = [siganl flattena map :^RACStream *(NSString *value) { NSLog(@" put %@ in the pan ",value); Return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber sendNext:@" "]; [subscriber sendCompleted]; return nil; }]; }]; Siganl = [siganl flattenMap:^RACStream *(id value) {NSLog(@" load %@ on the bank ",value); Return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {[subscriber sendNext:@" RACDisposable "]; [subscriber sendCompleted]; return nil; }]; }]; / / the last print Finally with = = = presentation [siganl subscribeNext: ^ (id) x {NSLog (@ "= = = = % @", x);}]. }Copy the code
13. The command
-(void)demo13{RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@"% @I surrender ",input); Return [RACDisposable *(id<RACSubscriber> subscriber) {return nil;}];}]; // Run the command [command execute:@" today "]; }Copy the code
Delay in 14.
- (void)demo14{ RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@" wait for me, I'm 10 seconds away "); [subscriber sendNext:@" North Pole "]; [subscriber sendCompleted]; return nil;}]; NSLog(@" wait for me, I'm 10 seconds away "); [subscriber sendCompleted]; return nil;}]; [[siganl delay:10] subscribeNext:^(id x) {NSLog(@" I'm here %@",x);}]; }Copy the code
15. The replay
- (void)demo15{ RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@" movie "); [subscriber sendNext:@" movie "]; [subscriber sendCompleted]; return nil;}]; NSLog(@" movie "); [subscriber sendCompleted]; return nil;}]; RACSignal *replaySiganl = [siganl replay]; // subscribeNext:^(NSString *x) {NSLog(@" %@",x);}]; [subscribeNext:^(NSString *x) {NSLog(@" %@",x);}]; }Copy the code
16. Timing – Take medicine every 8 hours
- (void)demo16{// Create a timer signal. RACSignal * SIGanl = [RACSignal interval:60 * 60 * 8 onScheduler:[RACSignal mainThreadScheduler]]; [siganl subscribeNext:^(id x) {NSLog(@" take ");}]; }Copy the code
17. A timeout
- (void)demo17{ RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@" I'm almost there "); RACSignal *sendSiganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:nil]; [subscriber sendCompleted]; return nil; }]; [[sendSiganl delay:60 * 70] subscribeNext:^(id x) SendNext :@" I'm here "]; [subscriber sendCompleted];}]; return nil;}]; [[siganl timeout:60 * 60 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) { NSLog(@" waiting for you for an hour, you didn't come, I'm leaving ");}]; }Copy the code
18. Retry
- (void)demo18{ __block int failedCount = 0; RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {if (failedCount < 100) {failedCount ++; NSLog(@" I failed "); [subscriber sendError:nil];}else{NSLog(@" After hundreds of times, I succeeded "); [subscriber sendNext:nil]; } return nil; }]; RACSignal *retrySiganl = [siganl retry]; // until the next ball occurs [retrySiganl subscribeNext:^(id x) {NSLog(@" important success ");}]; }Copy the code
19. Throttling, sorry, can only pass one person per second, if more than one person occurs in 1s, only the last one
- (void)demo19{ RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // Even if you send A next glass ball [subscriber sendNext:@"A"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"B"]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"C"]; [subscriber sendNext:@"D"]; [subscriber sendNext:@"E"]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"F"]; }); return nil; }]; [[signal throttle:1] subscribeNext:^(id x) {NSLog(@"%@ through ",x);}]; /* [2015-08-16 22:08:45.677] A [2015-08-16 22:08:46.737] B [2015-08-16 22:08:47.822] E [2015-08-16 22:08:48.920] F * /}Copy the code
20. Condition (takeUntil method, value until given signal completes)
- (void)demo20{ RACSignal *takeSiganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { RACSignal *siganl = [RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]; [siganl subscribeNext:^(id x) {// here subscribeNext ball [subscriber sendNext:@" to the end of the world "];}]; return nil;}]; RACSignal *conditionSiganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC))) Dispatch_get_main_queue (), ^{NSLog(@" world today, please get off "); [subscriber sendCompleted];}); return nil;}]; / / set conditions, takeSiganl signal before conditionSignal complete reception, constant value [[takeSiganl takeUntil: conditionSiganl] subscribeNext: ^ (id) x { NSLog(@"%@",x); }]; }Copy the code
21. RACReplaySubject use
/** * create RACReplaySubject 1. Subscribing signal 3. Sending signal workflow: 1. Subscribing signal, which internally saves the subscriber and the corresponding block 2 of the subscriber. When the signal is sent, the subscriber is traversed, calling the subscriber's nextBlock 3. */ -(void)RACReplaySubject{*/ -(void)RACReplaySubject{*/ -(void)RACReplaySubject{*/ -(void)RACReplaySubject RACReplaySubject *replaySubject = [RACReplaySubject subject]; [replaySubject subscribeNext:^(id x) { NSLog(@" 1 %@",x); }]; [replaySubject subscribeNext:^(id x) { NSLog(@"2 %@",x); }]; [replaySubject sendNext:@7]; [replaySubject subscribeNext:^(id x) { NSLog(@"3 %@",x); }]; }Copy the code
22. Rac_liftSelector: withSignals use
When signalA and signalB have both sent next at least once, then as soon as either signal has a new message, (void)test{RACSignal *sigalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber>) Subscriber) {double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds *NSEC_PER_SEC)); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(popTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"A"]; }); return nil; }]; RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"B"]; [subscriber sendNext:@"Another B"]; [subscriber sendCompleted]; return nil; }]; [self rac_liftSelector:@selector(doA:withB:) withSignals:sigalA,signalB, nil]; }Copy the code
Source: Summary of iOS RAC Use by Wei Yuchen