Foreplay
Personally, I highly value ReactiveCocoa. It is like Chinese Tai Chi. Tai Chi generates Liangyi, Liangyi generates Sixiang, Sixiang generates Bagua, and Bagua generates everything. ReactiveCocoa is a highly abstract programming framework. It is really abstract. At first glance, you don't know what it is for. After you use it, you will find that with it, you can do whatever you want. The coding has never been so smooth.
I won't talk about the principle of ReactiveCocoa here, because what can't be explained clearly is called abstraction. I will not mention the relevant concepts. I just want you to see how cool I am with it.
Code 48 hand
1. Observation RACObserve
Don't move. I'll know if you move. (observer RACObserve)
@weakify(self); [RACObserve(self, value) subscribeNext:^(NSString* x) { @strongify(self); NSLog(@"You moved"); }];
2. Unilateral binding RAC
You sing, I dance.
The content length of textField is implicitly reflected as a BOOL value and bound to the enable attribute of confirmButton. When the input content of textField is not empty, the enable of confirmButton = yes.
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"sing"]; [subscriber sendCompleted]; return nil; }]; RAC(self, value) = [signalA map:^id(NSString* value) { if ([value isEqualToString:@"sing"]) { return @"dance"; } return @""; }];
3. Bilateral RACChannelTo
If you go west, he will go east. If he goes left, you will go right.
RACChannelTerminal *channelA = RACChannelTo(self, valueA); RACChannelTerminal *channelB = RACChannelTo(self, valueB); [[channelA map:^id(NSString *value) { if ([value isEqualToString:@"west"]) { return @"east"; } return value; }] subscribe:channelB]; [[channelB map:^id(NSString *value) { if ([value isEqualToString:@"Left"]) { return @"right"; } return value; }] subscribe:channelA]; //Observe the change of valueA [[RACObserve(self, valueA) filter:^BOOL(id value) { return value ? YES : NO; }] subscribeNext:^(NSString* x) { NSLog(@"You to%@", x); }]; [[RACObserve(self, valueB) filter:^BOOL(id value) { return value ? YES : NO; }] subscribeNext:^(NSString* x) { NSLog(@"He to%@", x); }]; self.valueA = @"west"; self.valueB = @"Left";
2015-08-15 20:14:46.544 Test[2440:99901] you go west
2015-08-15 20:14:46.544 Test[2440:99901] He Xiang Dong
2015-08-15 20:14:46.545 Test[2440:99901] he left
2015-08-15 20:14:46.545 Test[2440:99901] you right
4. Proxy Protocol
You are a programmer. Please write an app for me.
@protocol Programmer - (void)makeAnApp; @end //Declare that you want to implement a proxy method in the protocol RACSignal *ProgrammerSignal = [self rac_signalForSelector:@selector(makeAnApp) fromProtocol:@protocol(Programmer)]; //Implementation of protocol method [ProgrammerSignal subscribeNext:^(RACTuple* x) { NSLog(@"It took a month, app It's done"); }]; //call [self makeAnApp];
2015-08-15 20:46:45.720 Test[2817:114564] took a month and the app was written
5. Broadcast NSNotificationCenter
Knowing your channel, I can hear you.
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"Code channel" object:nil] subscribeNext:^(NSNotification* x) { NSLog(@"skill:%@", x.userInfo[@"skill"]); }]; [[NSNotificationCenter defaultCenter] postNotificationName:@"Code channel" object:nil userInfo:@{@"skill":@"Write carefully"}];
2015-08-15 20:41:15.786 Test[2734:111505] skill: write carefully
6. Connect concat
Life is a story after story.
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"I'm in love"]; [subscriber sendCompleted]; return nil; }]; RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"I'm married"]; [subscriber sendCompleted]; return nil; }]; [[signalA concat:signalB] subscribeNext:^(id x) { NSLog(@"%@",x); }];
2015-08-15 12:19:46.707 Test[1845:64122] I'm in love
2015-08-15 12:19:46.707 Test[1845:64122] I'm married
7. merge
Sewage should flow into the sewage treatment plant for treatment.
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"Paper mill sewage"]; return nil; }]; RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"Electroplating plant sewage"]; return nil; }]; [[RACSignal merge:@[signalA, signalB]] subscribeNext:^(id x) { NSLog(@"handle%@",x); }];
2015-08-15 12:10:05.371 Test[1770:60147] treatment of paper mill wastewater
2015-08-15 12:10:05.372 Test[1770:60147] treatment of wastewater from electroplating plant
8. Combine latest
You are red, I am yellow, we are red and yellow, you are white, I haven't changed, we are white and yellow.
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"red"]; [subscriber sendNext:@"white"]; return nil; }]; RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"white"]; return nil; }]; [[RACSignal combineLatest:@[signalA, signalB]] subscribeNext:^(RACTuple* x) { RACTupleUnpack(NSString *stringA, NSString *stringB) = x; NSLog(@"We are%@%@of", stringA, stringB); }];
2015-08-15 12:14:19.837 Test[1808:62042] we are red and yellow
2015-08-15 12:14:19.837 Test[1808:62042] we are white and yellow
9. Compress zipWith
You are red, I am yellow, we are red and yellow, you are white, I haven't changed, oh, wait until I change.
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"red"]; [subscriber sendNext:@"white"]; return nil; }]; RACSignal *signalB = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"white"]; return nil; }]; [[signalA zipWith:signalB] subscribeNext:^(RACTuple* x) { RACTupleUnpack(NSString *stringA, NSString *stringB) = x; NSLog(@"We are%@%@of", stringA, stringB); }];
2015-08-15 20:34:24.274 Test[2660:108483] we are red and white
10. map
I can turn stone into gold.
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"stone"]; return nil; }] map:^id(NSString* value) { if ([value isEqualToString:@"stone"]) { return @"gold"; } return value; }]; [signal subscribeNext:^(id x) { NSLog(@"%@", x); }];
2015-08-16 20:00:12.853 Test[740:15871] gold
11. Reduce combineLatest:reduce:
Sugar is changed into sugar water by adding water.
RACSignal *sugarSignal = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"sugar"]; return nil; }]; RACSignal *waterSignal = [RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"water"]; return nil; }]; [[RACSignal combineLatest:@[sugarSignal, waterSignal] reduce:^id (NSString* sugar, NSString*water){ return [sugar stringByAppendingString:water]; }] subscribeNext:^(id x) { NSLog(@"%@", x); }];
2015-08-16 20:07:00.356 Test[807:19177] sugar water
12. filter
No entry under the age of 18.
[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@(15)]; [subscriber sendNext:@(17)]; [subscriber sendNext:@(21)]; [subscriber sendNext:@(14)]; [subscriber sendNext:@(30)]; return nil; }] filter:^BOOL(NSNumber* value) { return value.integerValue >= 18; }] subscribeNext:^(id x) { NSLog(@"%@", x); }];
2015-08-16 20:11:20.071 Test[860:21214] 21
2015-08-16 20:11:20.071 Test[860:21214] 30
13. Flat flattenMap
Beat egg liquid, fry eggs and serve.
[[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"Beat egg liquid"); [subscriber sendNext:@"Egg liquid"]; [subscriber sendCompleted]; return nil; }] flattenMap:^RACStream *(NSString* value) { return [RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"hold%@Pour it into the pan and fry it",value); [subscriber sendNext:@"Fried Eggs"]; [subscriber sendCompleted]; return nil; }]; }] flattenMap:^RACStream *(NSString* value) { return [RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"hold%@Put it on a plate", value); [subscriber sendNext:@"Serve"]; [subscriber sendCompleted]; return nil; }]; }] subscribeNext:^(id x) { NSLog(@"%@", x); }];
2015-08-16 20:39:34.786 Test[1226:34386] beat egg liquid
2015-08-16 20:39:34.787 Test[1226:34386] pour the egg liquid into the pot and fry it
2015-08-16 20:39:34.787 Test[1226:34386] put fried eggs in a plate
2015-08-16 20:39:34.787 Test[1226:34386] serving
14. Order then
It only takes three steps to put the elephant into the refrigerator: open the refrigerator door, put the elephant into the refrigerator, and close the refrigerator door.
[[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"Open the refrigerator door"); [subscriber sendCompleted]; return nil; }] then:^RACSignal *{ return [RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"Put the elephant in the fridge"); [subscriber sendCompleted]; return nil; }]; }] then:^RACSignal *{ return [RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"Close the refrigerator door"); [subscriber sendCompleted]; return nil; }]; }] subscribeCompleted:^{ NSLog(@"Stuffed the elephant into the fridge"); }];
2015-08-16 20:45:27.724 Test[1334:37870] open the refrigerator door
2015-08-16 20:45:27.725 Test[1334:37870] stuffed the elephant into the refrigerator
2015-08-16 20:45:27.725 Test[1334:37870] close the refrigerator door
2015-08-16 20:45:27.726 Test[1334:37870] stuffed the elephant into the refrigerator
15. Command RACCommand
I command you to surrender at once.
RACCommand *aCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { return [RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"I Surrender "); [subscriber sendCompleted]; return nil; }]; }]; [aCommand execute:nil];
2015-08-16 20:54:32.492 Test[1450:41849] I surrendered
16. delay
Wait for me. I'll be there in 10 seconds.
[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"Wait for me. I'll be there in 10 seconds"); [subscriber sendNext:nil]; [subscriber sendCompleted]; return nil; }] delay:10] subscribeNext:^(id x) { NSLog(@"I have arrived"); }];
2015-08-16 21:00:57.622 Test[1619:45924] wait for me. I'll be there in 10 seconds
2015-08-16 21:01:07.624 Test[1619:45924] I'm here
17. replay
Make once and watch many times.
RACSignal *replaySignal = [[RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"The big director made a film "my male ticket is a programmer""); [subscriber sendNext:@"<My male ticket is "programmer""]; return nil; }] replay]; [replaySignal subscribeNext:^(id x) { NSLog(@"Xiao Ming saw it%@", x); }]; [replaySignal subscribeNext:^(id x) { NSLog(@"Xiao Hong also saw it%@", x); }];
2015-08-16 21:18:38.002 Test[1854:54712] the great director made a film my male ticket is a programmer
2015-08-16 21:18:38.004 Test[1854:54712] Xiao Ming watched my male ticket is a programmer
2015-08-16 21:18:38.004 Test[1854:54712] Xiao Hong also watched my male ticket is a programmer
18. Timing interval
Take the medicine every 8 hours.
[[RACSignal interval:60*60*8 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) { NSLog(@"Take medicine"); }];
19. timeout
I've been waiting for you for an hour. You haven't come yet. I'm leaving.
[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { [[[RACSignal createSignal:^RACDisposable *(idsubscriber) { NSLog(@"I'm coming"); [subscriber sendNext:nil]; [subscriber sendCompleted]; return nil; }] delay:60*70] subscribeNext:^(id x) { [subscriber sendNext:nil]; [subscriber sendCompleted]; }]; return nil; }] timeout:60*60 onScheduler:[RACScheduler mainThreadScheduler]] subscribeError:^(NSError *error) { NSLog(@"I've been waiting for you for an hour. You haven't come yet. I'm leaving"); }];
2015-08-16 21:40:09.068 Test[2041:64720] I'm almost there
2015-08-16 22:40:10.048 Test[2041:64720] I've been waiting for you for an hour. You haven't come yet. I'm leaving
20. retry
It may take hundreds of failures before success.
__block int failedCount = 0; [[[RACSignal createSignal:^RACDisposable *(idsubscriber) { if (failedCount < 100) { failedCount++; NSLog(@"I failed."); [subscriber sendError:nil]; }else{ NSLog(@"After hundreds of failures"); [subscriber sendNext:nil]; } return nil; }] retry] subscribeNext:^(id x) { NSLog(@"Finally succeeded"); }];
2015-08-16 21:59:07.159 Test[2411:77080] I failed
2015-08-16 21:59:07.159 Test[2411:77080] I failed
2015-08-16 21:59:07.159 Test[2411:77080] I failed
2015-08-16 21:59:07.159 Test[2411:77080] I failed
2015-08-16 21:59:07.160 Test[2411:77080] I failed
2015-08-16 21:59:07.160 Test[2411:77080] I failed
2015-08-16 21:59:07.161 Test[2411:77080] I failed
2015-08-16 21:59:07.162 Test[2411:77080] I failed
...
2015-08-16 21:59:07.162 Test[2411:77080] I failed
2015-08-16 21:59:07.163 Test[2411:77080] I failed
2015-08-16 21:59:07.163 Test[2411:77080] I failed
2015-08-16 21:59:07.163 Test[2411:77080] I failed
2015-08-16 21:59:07.164 Test[2411:77080] I failed
2015-08-16 21:59:07.164 Test[2411:77080] I failed
2015-08-16 21:59:07.164 Test[2411:77080] I failed
2015-08-16 21:59:07.165 Test[2411:77080] after hundreds of failures
2015-08-16 21:59:07.165 Test[2411:77080] finally succeeded
21. throttle
Sorry, there can only be one person in a second.
[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { [subscriber sendNext:@"passenger A"]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"passenger B"]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"passenger C"]; [subscriber sendNext:@"passenger D"]; [subscriber sendNext:@"passenger E"]; }); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"passenger F"]; }); return nil; }] throttle:1] subscribeNext:^(id x) { NSLog(@"%@Yes",x); }];
2015-08-16 22:08:45.677 Test[2618:83764] passenger A
2015-08-16 22:08:46.737 Test[2618:83764] passenger B
2015-08-16 22:08:47.822 Test[2618:83764] passenger E
2015-08-16 22:08:48.920 Test[2618:83764] passenger F
22. Condition takeUntil
We can't be separated until the end of the world.
[[[RACSignal createSignal:^RACDisposable *(idsubscriber) { [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) { [subscriber sendNext:@"We can't be separated until the end of the world"]; }]; return nil; }] takeUntil:[RACSignal createSignal:^RACDisposable *(idsubscriber) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"The end of the world has come"); [subscriber sendNext:@"The end of the world has come"]; }); return nil; }]] subscribeNext:^(id x) { NSLog(@"%@", x); }];
2015-08-16 22:17:22.648 Test[2766:88737] we can't be separated until the end of the world
2015-08-16 22:17:23.648 Test[2766:88737] we can't be separated until the end of the world
2015-08-16 22:17:24.645 Test[2766:88737] we can't be separated until the end of the world
2015-08-16 22:17:25.648 Test[2766:88737] we can't be separated until the end of the world
2015-08-16 22:17:26.644 Test[2766:88737] we can't be separated until the end of the world
2015-08-16 22:17:26.645 Test[2766:88737] the end of the world has come
Finish
ReactiveCocoa is so elegant that once used, it can't stop at all. It's just the tip of the iceberg. I hope I can arouse your interest.