不用RAC,如何ie请求数据成功,回调方法出错类方法里的block

主题 : 不用RAC,如何回调类方法里的block?
级别: 新手上路
UID: 505925
可可豆: 135 CB
威望: 130 点
在线时间: 241(时)
发自: Web Page
来源于&&分类
不用RAC,如何回调类方法里的block?&&&
```+ (void)showAlertWithType:(NSInteger)type buttonClickedBlock:(void (^)(void))buttonClickedBlock {&&&&&&&&UIWindow *delegateWindow = [[[UIApplication sharedApplication] delegate] window];&&&&&&&&// 灰色view&&&&UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(90, 90, 200, 200)];&&&&[delegateWindow addSubview:bgView];&&&&bgView.backgroundColor = [UIColor grayColor];&&&&&&&&// 按钮(点击按钮让灰色view变成红色)&&&&UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];&&&&[bgView addSubview:button];&&&&button.frame = CGRectMake(30, 30, 90, 40);&&&&[button setTitle:@&点击变红& forState:UIControlStateNormal];&&&&&&&&// 怎么实现点击按钮让灰色view变红并且执行block?(不使用RAC)&&&&//button addTarget:&#(nullable id)#& action:&#(nonnull SEL)#& forControlEvents:&#(UIControlEvents)#&}```这个类方法是弹出一个灰色view,灰色view上有一个按钮,现在我想点击这个按钮后让灰色view的颜色变成红色并且回调block。问:如果不用RAC,你们会怎么实现?
级别: 新手上路
UID: 523341
可可豆: 48 CB
威望: 46 点
在线时间: 299(时)
发自: Web Page
级别: 新手上路
可可豆: 62 CB
威望: 62 点
在线时间: 327(时)
发自: Web Page
看不懂啊,根本不需要RAC就能简单实现。。。可能我没理解LZ意思吧
级别: 新手上路
可可豆: 16 CB
威望: 7 点
在线时间: 36(时)
发自: Web Page
很简单,灰色view用自定义view,比如MyView,然后button的target设置为MyView实例对象,action对应MyView类中的一个实例方法
级别: 新手上路
UID: 505925
可可豆: 135 CB
威望: 130 点
在线时间: 241(时)
发自: Web Page
回 3楼(Daniate) 的帖子
感谢分享,get了
级别: 骑士
可可豆: 250 CB
威望: 250 点
在线时间: 760(时)
发自: Web Page
你这是想在类方法中加个点击事件,然后点击事件响应的时候回调block吧。
@property (nonatomic, strong) UIButton *
@property (nonatomic, copy) void (^action)();
+ (CKAlertController *)clickButton:(void (^)())block {
&&&&CKAlertController * alert = [CKAlertController new];
&&&&alert.view.backgroundColor = [UIColor colorWithWhite:1 alpha:0.3];
&&&&alert.action =
&&&&[alert.view addSubview:alert.button];
// 按钮响应
- (void)buttonAction {
&&&&if (self.action) self.action();
#pragma mark - -- 懒加载
- (UIButton *)button {
&&&&if (!_button) {
&&&&&&&&_button = [UIButton buttonWithType:UIButtonTypeCustom];
&&&&&&&&_button.frame = CGRectMake(200, 200, 50, 50);
&&&&&&&&_button.backgroundColor = [UIColor redColor];
&&&&&&&&[_button addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
&&&&return _
级别: 新手上路
UID: 505925
可可豆: 135 CB
威望: 130 点
在线时间: 241(时)
发自: Web Page
回 5楼(a) 的帖子
可以,这很强????
级别: 骑士
可可豆: 250 CB
威望: 250 点
在线时间: 760(时)
发自: Web Page
回 6楼(无夜之星辰) 的帖子
三个问号是啥意思
级别: 新手上路
UID: 505925
可可豆: 135 CB
威望: 130 点
在线时间: 241(时)
发自: Web Page
回 7楼(a) 的帖子
是“赞”的表情,CocoaChina显示乱码
关注本帖(如果有新回复会站内信通知您)
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 关注CVP公众号
扫一扫 浏览移动版ReactiveCocoa学习笔记
时间: 15:27:02
&&&& 阅读:171
&&&& 评论:
&&&& 收藏:0
标签:几个月前看了一点RAC的介绍,感觉很强大但也很难入门,这次挖个坑,整理下RAC的资源。
ReactiveCocoa 受&激发。不同于使用可变的变量替换和就地修改,RAC提供Signals(被表示为RACSignal&)来捕获当前值和将来值。
通过链接(chaining),组合(combining)和对Signals做出反应(reacting),我们不必频繁地观察并更新值,而是声明式编写软件。
比如,文本域可以绑定到最新的时间,当它变化时,不需用额外的代码来观察时间每秒钟更新文本域。它类似KVO,但是用blocks替代了重写&-observeValueForKeyPath:ofObject:change:context:&。
Signals也可以表示异步操作,很像&。这极大地简化了异步编码,包括网络方面的代码。
RAC一个重要的优点就是它提供了单独的、统一的方法来处理异步行为,包括委托方法,回调blocks,target-action机制,通知和KVO。
这有一个简单的例子:
// When self.username changes, logs the new name to the console.//// RACObserve(self, username) creates a new RACSignal that sends the current// value of self.username, then the new value whenever it changes.// -subscribeNext: will execute the block whenever the signal sends a value.[RACObserve(self, username) subscribeNext:^(NSString *newName) {
NSLog(@"%@", newName);}];
但是不同于KVO通知,signals可以链接在一起操作:
// Only logs names that starts with "j".//// -filter returns a new RACSignal that only sends a new value when its block// returns YES.[[RACObserve(self, username)
filter:^(NSString *newName) {
return [newName hasPrefix:@"j"];
subscribeNext:^(NSString *newName) {
NSLog(@"%@", newName);
Signals也可以被用于导出状态。不必观察属性然后设置其他属性来响应这个属性新的值,RAC可以依照signals和操作来表达属性:
// Creates a one-way binding so that self.createEnabled will be// true whenever self.password and self.passwordConfirmation// are equal.//// RAC() is a macro that makes the binding look nicer.// // +combineLatest:reduce: takes an array of signals, executes the block with the// latest value from each signal whenever any of them changes, and returns a new// RACSignal that sends the return value of that block as values.RAC(self, createEnabled) = [RACSignal
combineLatest:@[ RACObserve(self, password), RACObserve(self, passwordConfirmation) ]
reduce:^(NSString *password, NSString *passwordConfirm) {
return @([passwordConfirm isEqualToString:password]);
Signals可以建立在任意值随时间的流动上,不仅仅是KVO。比如,它们也能表示按钮被按下:
// Logs a message whenever the button is pressed.//// RACCommand creates signals to represent UI actions. Each signal can// represent a button press, for example, and have additional work associated// with it.//// -rac_command is an addition to NSButton. The button will send itself on that// command whenever it‘s pressed.self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
NSLog(@"button was pressed!");
return [RACSignal empty];}];
或者异步网络操作:
// Hooks up a "Log in" button to log in over the network.//// This block will be run whenever the login command is executed, starting// the login process.self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) {
// The hypothetical -logIn method returns a signal that sends a value when
// the network request finishes.
return [client logIn];}];// -executionSignals returns a signal that includes the signals returned from// the above block, one for each time the command is executed.[self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {
// Log a message whenever we log in successfully.
[loginSignal subscribeCompleted:^{
NSLog(@"Logged in successfully!");
}];}];// Executes the login command when the button is pressed.self.loginButton.rac_command = self.loginCommand;
Signals也能表示定时器,其他UI事件,或者任何其他随时间而改变的东西。
通过链接和转换这些Signals,可以为异步操作建立更加复杂的行为。在一组操作完成后,后续工作能容易地被触发:
// Performs 2 network operations and logs a message to the console when they are// both completed.//// +merge: takes an array of signals and returns a new RACSignal that passes// through the values of all of the signals and completes when all of the// signals complete.//// -subscribeCompleted: will execute the block when the signal completes.[[RACSignal
merge:@[ [client fetchUserRepos], [client fetchOrgRepos] ]]
subscribeCompleted:^{
NSLog(@"They‘re both done!");
Signals可以被链接起来按顺序地执行异步操作,而不用嵌套回调blocks。这类似&是如何经常使用的:
// Logs in the user, then loads any cached messages, then fetches the remaining// messages from the server. After that‘s all done, logs a message to the// console.//// The hypothetical -logInUser methods returns a signal that completes after// logging in.//// -flattenMap: will execute its block whenever the signal sends a value, and// returns a new RACSignal that merges all of the signals returned from the block// into a single signal.[[[[client
logInUser]
flattenMap:^(User *user) {
// Return a signal that loads cached messages for the user.
return [client loadCachedMessagesForUser:user];
flattenMap:^(NSArray *messages) {
// Return a signal that fetches any remaining messages.
return [client fetchMessagesAfterMessage:messages.lastObject];
subscribeNext:^(NSArray *newMessages) {
NSLog(@"New messages: %@", newMessages);
} completed:^{
NSLog(@"Fetched all messages.");
RAC甚至使绑定到异步操作结果更加容易:
// Creates a one-way binding so that self.imageView.image will be set the user‘s// avatar as soon as it‘s downloaded.//// The hypothetical -fetchUserWithUsername: method returns a signal which sends// the user.//// -deliverOn: creates new signals that will do their work on other queues. In// this example, it‘s used to move work to a background queue and then back to the main thread.//// -map: calls its block with each user that‘s fetched and returns a new// RACSignal that sends values returned from the block.RAC(self.imageView, image) = [[[[client
fetchUserWithUsername:@"joshaber"]
deliverOn:[RACScheduler scheduler]]
map:^(User *user) {
// Download the avatar (this is done on a background queue).
return [[NSImage alloc] initWithContentsOfURL:user.avatarURL];
// Now the assignment will be done on the main thread.
deliverOn:RACScheduler.mainThreadScheduler];
上面示范了RAC能做什么,但它没示范RAC为何这么强大。用README的篇幅的例子很难赞美RAC,但是它让编程有更加简化的状态,更少的饮用,更好的代码位置和更好的表达意图。
更多的例子,参见&或&, 都是用ReactiveCocoa写的真实的iOS应用&. 关于 RAC 更多的详细信息可以在&文件夹中找到.
我的学习笔记(不断更新)
函数式编程
参考维基百科上的&,简单理解为可以将函数作为其他函数的参数,具有block或&表达式。
响应式编程
参考维基百科上的&,简单地理解为专注于数据流和变化的传播。
RAC中的类和方法
RACSignal和RACStream
RAC的核心是Signal,对应的类为RACSignal,它其实是一个事件源,Signal会给它的订阅者(subscribers)发送一连串的事件。有三种事件:next,error和completed。Signal可以在error或completed事件发出前发出任意多的next事件。
RACSignal有很多方法用于订阅事件,查看RACSignal (Subscription)类别可以看到所有的订阅事件的方法,每个方法都会将类型为(void (^)(id x))的block作为参数,当事件发生时block中的代码会执行,例如&subscribeNext:&方法会传入一个block作为参数,当Signal的next事件发出后,block会接收到事件并执行。
RAC为UIKit添加了很多类别来让我们可以订阅UI组件的事件,比如UITextField (RACSignalSupport)中的rac_textSignal会在文本域内容变化时发出next事件。
事件包含的内容可以是类型,只要是对象就行,如果是一些数字,布尔值等字面量,可以用&@()&语法装箱成NSNumber。
RACSignal是RACStream的子类,RACStream是一个抽象类,描述了值的流动,列举一下它比较常用的操作(Operations类别):
filter:&对RACStream中的事件内容进行过滤,返回一个过滤事件内容后的instancetype&map:&会将事件中的数据转换成你想要的数据,返回一个转换事件内容后的instancetype&flattenMap:&在map的基础上使其flatten,也就是当Signal嵌套(一个Signal的事件是另一个Signal)的时候,会将内部Signal的事件传递给外部Signal&distinctUntilChanged&比较数值流中当前值和上一个值,如果不同,就返回当前值,简单理解为&流&的值有变化时反馈变化的值,求异存同。
PS:instancetype是程序运行时对象的类型,有可能为RACStream,也可以为其子类RACSignal。正是因为这些操作事件的方法都会返回事件源对象相同的类型,事件可以被一连串的被这些方法修改,过滤等,这就形成了管道,管道中传递着事件,包含着value。&建议管道的语法格式是每个操作新起一行,并在垂直方向上对齐:&&可惜Xcode的自动缩进并不会按照这样的格式对齐,是时候与它斗智斗勇啦!
RACSignal还有一些方法是对Signal做操作的,在RACSignal (Operations)类别中有详细的描述,比较常用的如下:
combineLatest:reduce:&将一组Signal发出的最新的事件合并成一个Signal,每当这组Signal发出新事件时,reduce的block会执行,将所有新事件的值合并成一个值,并当做合并后Signal的事件发出去。这个方法会返回合并后的Signal。&PS:关于reduce的block中参数,其实是与combineLatest中数组元素一一对应的,这里RAC用了一个黑魔法,参看
doNext:&这个向Signal管道上添加添加副作用。它并不会改变事件,参数block也没有返回值,它返回一个执行了block的Signal,这样block中的副作用就被注入到了以前的Signal。
then:&当一个订阅者被发送了completed事件后,&then:&方法才会执行,订阅者会订阅&then:&方法返回的Signal,这个Signal是在block中返回的。这样优雅的实现了从一个Signal到另一个Signal的订阅。
deliverOn:&参数为RACScheduler类的对象scheduler,这个方法会返回一个Signal,它的所有事件都会传递给scheduler参数所表示的线程,而以前管道上的副作用还会在以前的线程上。这个方法主要是切换线程。
subscribeOn:&功能跟&deliverOn:&相同,但是它也会将副作用也切换到制定线程中。
throttle:&它接收一个时间间隔interval作为参数,如果Signal发出的next事件之后interval时间内不再发出next事件,那么它返回的Signal会将这个next事件发出。也就是说,这个方法会将发送比较频繁的next事件舍弃,只保留一段&静默&时间之前的那个next事件,这个方法常用于处理输入框等信号(用户打字很快),因为它只保留用户最后输入的文字并返回一个新的Signal,将最后的文字作为next事件参数发出。
and&、&or&、&not&NSNumber中Bool的与、或、非操作,将Signal发出的事件内容转化。
还可以根据方法(SEL类型)来创建Signal,每当该方法被调用时,Signal都会将此方法被传入的参数打包成&RACTuple元组类型来发送next事件给它的接受者。&rac_signalForSelector:&和&rac_signalForSelector:fromProtocol:这两个方法都能通过指定的方法来创建Signal。
RACSubscriber
RACSubscriber是一个协议,包含了向订阅者发送事件的方法。
[RACSignal createSignal:^RACDisposable *(id&RACSubscriber& subscriber) {
[subscriber sendNext:@(YES)];
[subscriber sendCompleted];
return nil;
上面工厂方法用于创建一个Signal,当Signal被订阅时,&createSignal:&的参数block中的内容被执行。block的参数是一个实现RACSubscriber协议的对象,然后向这个订阅者发送了next事件(内容为NSNumber类型的@YES值)和completed事件。&PS:除此之外RACSubscriber还有&sendError:&和&didSubscribeWithDisposable:&两个方法。
RACDisposable
你会发现RACSignal (Subscription)类别中所有方法的返回值类型都是RACDisposable,它的&dispose&方法可以让我们手动移除订阅者。举个栗子:
RACSignal *backgroundColorSignal =
[self.searchText.rac_textSignal
map:^id(NSString *text) {
return [self isValidSearchText:text] ?
[UIColor whiteColor] : [UIColor yellowColor];
}]; RACDisposable *subscription =
[backgroundColorSignal
subscribeNext:^(UIColor *color) {
self.searchText.backgroundColor = color;
}]; // at some point in the future ...[subscription dispose];
当管道(好吧比较短)的订阅者全部被移除后,管道中的代码不会执行,包括三种事件参数block中的代码和诸如doNext:&等副作用的block。可以简单理解为,当管道中的Signal没人订阅,它的事件就不会发出了。
RACCommand
RACCommand&通常用来表示某个Action的执行,比如点击Button。
RACScheduler
类似于GCD中的序列,是管理线程的类,负责RAC中让信号发出的事件华丽丽的在线程中穿梭,尤其是想更新UI必须在主线程中的时候,可以让事件直接从其他线程跳到主线程。此外RACScheduler也有优先级、延时等GCD中的特性。
解决引用循环
使用RAC会写大量的block,这就会涉及到引用循环的问题,如果你细心的话会发现上一节的代码就存在这个问题,一种普遍的解决办法是声明一个weak变量,并将self赋值给它,然后再block中使用这个weak变量,但这样太繁琐了。
在这里又有一个语法糖:&@weakify()&和&@strongify&,想使用它,得先导入类头文件:&#import "RACEXTScope.h"。其实这个语法糖来自于&,有关它的原理请见&
于是上一节的代码可以改成下面这样:
@weakify(self)[[self.searchText.rac_textSignal
map:^id(NSString *text) {
return [self isValidSearchText:text] ?
[UIColor whiteColor] : [UIColor yellowColor];
subscribeNext:^(UIColor *color) {
@strongify(self)
self.searchText.backgroundColor = color;
常用宏定义
RAC()&可以将Signal发出事件的值赋值给某个对象的某个属性,其参数为对象名和属性名&RACObserve()&参数为对象名和属性名,新建一个Signal并对对象的属性的值进行观察,当值变化时Signal会发出事件
标签:原文地址:http://www.cnblogs.com/iamjjh/p/4747824.html
&&国之画&&&& &&&&chrome插件
版权所有 京ICP备号-2
迷上了代码!ReactiveCocoa (RAC) 框架 - IOS - 伯乐在线
& ReactiveCocoa (RAC) 框架
本文是根据在斗鱼直播ReactiveCocoa时整理的文章,同时加上本人的见解,若有错误希望指出。
感谢 DeveloperLx 为大家做出的贡献,虽然直播声音小了点,但满满的都是干货 ^v^
神马是RAC?ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。借用RayWenderlich上面的话:
As an iOS developer, nearly every line of code you write is in re a button tap, a received network message, a property change (via Key Value Observing) or a change in user’s location via CoreLocation are all good examples. However, these events are all encod as actions, delegates, KVO, callbacks and others. ReactiveCocoa defines a standard interface for events, so they can be more easily chained, filtered and composed using a basic set of tools.
翻译过来就是:
作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback等。ReactiveCocoa为事件定义了一个标准接口,从而可以使用一些基本工具来更容易的连接、过滤和组合。
RAC是由 Mattt Thompson 大神开发的,很多开发者对其的评价是开启一个新Objective-C纪元,可见对其评价有多高。
以下是RAC的Github主页:
以及官方给出的
ReactiveCocoa安装教程我就不说了,用pod安装即可。
本文的Demo可在文章最后下载,在阅读本文的时候,强烈推荐边看Demo边看博文。
项目中加入了ReactiveCocoa 和 DeveloperLx 大神的打印插件 。
同时加入了键盘相应的第三方,然而没有怎么用到。
以及,使用方法可以看这篇文章,。
第一部分 简单使用
文本框事件
原来我们在使用textFiled的时候我们需要写到
Objective-C
[textField addTarget:self action:@selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
[textField addTarget:self action:@selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
然后实现textChanged:方法,在RAC中,对于文本框的监听,是非常简单的一件事情,看如下代码:
Objective-C
UITextField * textField = ({
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
[self.view addSubview:textField];
@weakify(self); //
__weak __typeof__(self) self_weak_ =
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
// __strong __typeof__(self) self = self_weak_;
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
[[textField rac_signalForControlEvents:UIControlEventEditingChanged]
subscribeNext:^(id x) {
LxDBAnyVar(x);
[textField.rac_textSignal subscribeNext:^(NSString *x) {
LxDBAnyVar(x);
1234567891011121314151617181920212223242526
UITextField * textField = ({&&&&&& UITextField * textField = [[UITextField alloc]init];&&&&&& textField.backgroundColor = [UIColor cyanColor];&&&&&& &&&&&& textField;&& });&&[self.view addSubview:textField];&& && @weakify(self); //&&__weak __typeof__(self) self_weak_ =&& && [textField mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&& &&&&&& @strongify(self);&&&&// __strong __typeof__(self) self = self_weak_;&&&&&& make.size.mas_equalTo(CGSizeMake(180, 40));&&&&&& make.center.equalTo(self.view);&& }];&& && [[textField rac_signalForControlEvents:UIControlEventEditingChanged]&&&&subscribeNext:^(id x) {&&&&&&&&&&&&&&&&LxDBAnyVar(x);&&&&}];&& [textField.rac_textSignal subscribeNext:^(NSString *x) {&&&&&& &&&&&& LxDBAnyVar(x);&& }];
打印结果:
Objective-C
?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 12
?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&
?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 123
?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '1231'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&
?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 1231
?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '12312'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&
?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 12312
?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&
?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 123123
?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 12?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 123?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '1231'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 1231?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '12312'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 12312?__31-[ViewController textFiledTest]_block_invoke241 + 211? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0&; layer = 0x7fe810c51600&&?__31-[ViewController textFiledTest]_block_invoke_2 + 215? x = 123123
我们很容易的监听到textFiled中发生的变化,其中x的类型默认为id类型, 我们已知它的类型的时候我们可以将其改变,就像上面代码,将id改成了NSString类型。
Objective-C
self.view.userInteractionEnabled = YES;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];
[[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer * tap) {
LxDBAnyVar(tap);
[self.view addGestureRecognizer:tap];
self.view.userInteractionEnabled = YES;&&&&UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];&&&&[[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer * tap) {&&&&&&&&&&&&&&&&LxDBAnyVar(tap);&&&&}];&&&&[self.view addGestureRecognizer:tap];
为了方便,我们直接添加到self.view上,点击屏幕,得到打印结果:
Objective-C
?__29-[ViewController gestureTest]_block_invoke + 184? tap = 0x7fa2e3e1f9f0; state = E view = 0x7fa2e3e20b70&; target= action=sendNext:, target=0x7fa2e3c064f0&)&&
?__29-[ViewController gestureTest]_block_invoke + 184? tap = 0x7fa2e3e1f9f0; state = Ended; view = 0x7fa2e3e20b70&; target= action=sendNext:, target=0x7fa2e3c064f0&)&&
Objective-C
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(NSNotification * notification) {
LxDBAnyVar(notification);
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(NSNotification * notification) {&&&&&& &&&&&& LxDBAnyVar(notification);&& }];
我们建立了一个通知,叫做进入后台, 当程序进入后台的时候通知相应,当我们用RAC写通知的时候,我们有一个好处,就是不用removeObserver通知,因为RAC通知的监听者师RAC自己,它会帮你管理释放方法。可以看方法实现如下:
Objective-C
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
@unsafeify(object);
return [[RACSignal createSignal:^(idRACSubscriber& subscriber) {
@strongify(object);
id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note];
return [RACDisposable disposableWithBlock:^{
[self removeObserver:observer];
}] setNameWithFormat:@"-rac_addObserverForName: %@ object: ", notificationName, [object class], object];
12345678910111213
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object { @unsafeify(object); return [[RACSignal createSignal:^(idRACSubscriber& subscriber) {
@strongify(object);
id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note];
return [RACDisposable disposableWithBlock:^{
[self removeObserver:observer];
}]; }] setNameWithFormat:@"-rac_addObserverForName: %@ object: ", notificationName, [object class], object];}
Objective-C
//1. 延迟某个时间后再做某件事
[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
LxPrintAnything(rac);
//2. 每间隔多长时间做一件事
[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {
LxDBAnyVar(date);
1234567891011
//1. 延迟某个时间后再做某件事[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{&&&&&&&&LxPrintAnything(rac);}];&//2. 每间隔多长时间做一件事[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {&&&&&&&&LxDBAnyVar(date);}];
这是定时器最常用的两种写法,第一种方法,延迟时间去做某件事,更改afterDelay的属性。
第二种方法,每间隔多长时间做一件事,更改interval属性。
Objective-C
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"RAC" message:@"ReactiveCocoa" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ensure", nil];
[[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) {
LxDBAnyVar(tuple);
LxDBAnyVar(tuple.first);
LxDBAnyVar(tuple.second);
LxDBAnyVar(tuple.third);
[alertView show];
// 更简单的方式:
[[alertView rac_buttonClickedSignal]subscribeNext:^(id x) {
LxDBAnyVar(x);
123456789101112131415161718
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"RAC" message:@"ReactiveCocoa" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ensure", nil];&& && [[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) {&&&&&& &&&&&& LxDBAnyVar(tuple);&&&&&& &&&&&& LxDBAnyVar(tuple.first);&&&&&& LxDBAnyVar(tuple.second);&&&&&& LxDBAnyVar(tuple.third);&& }];&& [alertView show];&& && && // 更简单的方式:&& [[alertView rac_buttonClickedSignal]subscribeNext:^(id x) {&&&&&& &&&&&& LxDBAnyVar(x);&& }];
用RAC去写代理的时候,会有局限,只能取代没有返回值的代理方法,什么是没有返回值的代理呢?比如说tableView的代理方法:
Objective-C
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath&&- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
这两个方法一个返回的是CGFloat,一个是void,RAC只能取代void的代理。
Objective-C
UIScrollView * scrollView = [[UIScrollView alloc]init];
scrollView.delegate = (id)
[self.view addSubview:scrollView];
UIView * scrollViewContentView = [[UIView alloc]init];
scrollViewContentView.backgroundColor = [UIColor yellowColor];
[scrollView addSubview:scrollViewContentView];
@weakify(self);
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(80, 80, 80, 80));
[scrollViewContentView mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.edges.equalTo(scrollView);
make.size.mas_equalTo(CGSizeMake(CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)));
[RACObserve(scrollView, contentOffset) subscribeNext:^(id x) {
LxDBAnyVar(x);
123456789101112131415161718192021222324252627
UIScrollView * scrollView = [[UIScrollView alloc]init];scrollView.delegate = (id)self;[self.view addSubview:scrollView];&UIView * scrollViewContentView = [[UIView alloc]init];scrollViewContentView.backgroundColor = [UIColor yellowColor];[scrollView addSubview:scrollViewContentView];&@weakify(self);&[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&&&&@strongify(self);&&&&make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(80, 80, 80, 80));}];&[scrollViewContentView mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&&&&@strongify(self);&&&&make.edges.equalTo(scrollView);&&&&make.size.mas_equalTo(CGSizeMake(CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)));}];&[RACObserve(scrollView, contentOffset) subscribeNext:^(id x) {&& &&&&LxDBAnyVar(x);}];
用RAC写KVO的好处就是方法简单,keypath有代码提示。
第二部分 进阶
Objective-C
- (RACSignal *)loginSignal
return [RACSignal createSignal:^RACDisposable *(idsubscriber) {
RACDisposable * schedulerDisposable = [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
if (arc4random()%10 & 1) {
[subscriber sendNext:@"Login response"];
[subscriber sendCompleted];
[subscriber sendError:[NSError errorWithDomain:@"LOGIN_ERROR_DOMAIN" code:444 userInfo:@{}]];
return [RACDisposable disposableWithBlock:^{
[schedulerDisposable dispose];
1234567891011121314151617181920212223
- (RACSignal *)loginSignal&&{&&&&&&return [RACSignal createSignal:^RACDisposable *(idsubscriber) {&&&&&&&&&&&&&&&&&&&&RACDisposable * schedulerDisposable = [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{&&&&&&&&&&&& &&&&&&&&&&&&&&if (arc4random()%10 & 1) {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&[subscriber sendNext:@"Login response"];&&&&&&&&&&&&&&&&&&[subscriber sendCompleted];&&&&&&&&&&&&&&}&&&&&&&&&&&&&&else {&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&[subscriber sendError:[NSError errorWithDomain:@"LOGIN_ERROR_DOMAIN" code:444 userInfo:@{}]];&&&&&&&&&&&&&&}&&&&&&&&&&}];&&&&&&&&&&&&&&&&&&&&return [RACDisposable disposableWithBlock:^{&&&&&&&&&&&&&&&&&&&&&&&&&&&&[schedulerDisposable dispose];&&&&&&&&&&}];&&&&&&}];&&}
RAC的核心就是RACSignal,也就是信号,我们可以直接创建信号createSignal,并发送它sendNext,当信号完成后我们同时用dispose方法销毁它。发送信号,我们同时也要订阅信号,订阅信号代码如下:
Objective-C
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
} error:^(NSError *error) {
LxDBAnyVar(error);
} completed:^{
LxPrintAnything(completed);
12345678910
[signal subscribeNext:^(id x) {&&&& &&&& LxDBAnyVar(x); } error:^(NSError *error) {&&&& &&&& LxDBAnyVar(error); } completed:^{&&&& &&&& LxPrintAnything(completed); }];
在信号发送的时候, 错误的时候,以及完成的时候,我们都可以得到相应。
信号的处理
map (映射)
Objective-C
UITextField * textField = ({
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
[self.view addSubview:textField];
@weakify(self); //
__weak __typeof__(self) self_weak_ =
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
// __strong __typeof__(self) self = self_weak_;
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
[[textField.rac_textSignal map:^id(NSString *text) {
LxDBAnyVar(text);
return @(text.length);
}] subscribeNext:^(id x) {
LxDBAnyVar(x);
1234567891011121314151617181920212223242526
UITextField * textField = ({&&&&&&&&UITextField * textField = [[UITextField alloc]init];&&&&&&&&textField.backgroundColor = [UIColor cyanColor];&&&&&&&&&&&&&&&&textField;&&&&});&&&&[self.view addSubview:textField];&&&&&&&&@weakify(self); //&&__weak __typeof__(self) self_weak_ =&&&&&&&&[textField mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&&&&&&&&&&&&@strongify(self);&&&&// __strong __typeof__(self) self = self_weak_;&&&&&&&&make.size.mas_equalTo(CGSizeMake(180, 40));&&&&&&&&make.center.equalTo(self.view);&&&&}];&&&&&[[textField.rac_textSignal map:^id(NSString *text) {&&&&&&&&&&&&&& LxDBAnyVar(text);&&&&&&&&&&&&&&&&return @(text.length);&&&&&&&&&&&&}] subscribeNext:^(id x) {&&&&&&&& LxDBAnyVar(x);&&&&}];
map这个函数,在这里不是地图的意思,代表映射。map能做的事情就是把监听的rac_textSignal所返回的值,替换成别的就像上面代码中的text的长度。
为了方便演示,我就不再赋值创建textField的代码了,请到Demo中查看
Objective-C
[[[textField.rac_textSignal map:^id(NSString *text) {
LxDBAnyVar(text);
return @(text.length);
}]filter:^BOOL(NSNumber *value) {
return value.integerValue & 3;
}] subscribeNext:^(id x) {
LxDBAnyVar(x);
12345678910111213
[[[textField.rac_textSignal map:^id(NSString *text) {&&&&&&&&&&&&&& LxDBAnyVar(text);&&&&&&&&&&&&&&&&return @(text.length);&&&&&&&&&&&&}]filter:^BOOL(NSNumber *value) {&&&&&&&&&&&&&&&&return value.integerValue & 3;&&&&&&&&&&&&}] subscribeNext:^(id x) {&&&&&&&& LxDBAnyVar(x);&&&&}];
filter是个BOOL值,它代表的是一个条件,当这个条件发生的时候才会作出相应,比如上面代码中,当长度大于3的时候,才会打印x的值。
Objective-C
//创建信号
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
}]delay:2];
LxPrintAnything(start);
//创建订阅者
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
1234567891011
//创建信号&&&&RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {&&&&&&&&[subscriber sendNext:@"rac"];&&&&&&&&[subscriber sendCompleted];&&&&&&&&return nil;&&&&}]delay:2];&&&&LxPrintAnything(start);&&&&//创建订阅者&&&&[signal subscribeNext:^(id x) {&&&&&&&&LxDBAnyVar(x);&&&&}];
delay的作用就是延迟,或者说等待,如上,等待2秒之后打印了x。
Objective-C
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(idRACSubscriber& subscriber) {
[subscriber sendNext:@"123"];//startWith:@"123"等同于这句话 也就是第一个发送,主要是位置
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
}]startWith:@"123"];
LxPrintAnything(start);
//创建订阅者
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
123456789101112
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(idRACSubscriber& subscriber) {&&&&&&&&//&&&&&&&&[subscriber sendNext:@"123"];//startWith:@"123"等同于这句话 也就是第一个发送,主要是位置&&&&&&&&[subscriber sendNext:@"rac"];&&&&&&&&[subscriber sendCompleted];&&&&&&&&return nil;&&&&}]startWith:@"123"];&&&&LxPrintAnything(start);&&&&//创建订阅者&&&&[signal subscribeNext:^(id x) {&&&&&&&&LxDBAnyVar(x);&&&&}];
startWith也就是最开始的意思,看以上代码 startWith:@"123"等同于[subscriber sendNext:@"123"] 也就是第一个发送,主要是位置.
Objective-C
[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
[[RACScheduler mainThreadScheduler]afterDelay:3 schedule:^{
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]]
subscribeNext:^(id x) {
LxDBAnyVar(x);
} error:^(NSError *error) {
LxDBAnyVar(error);
} completed:^{
LxPrintAnything(completed);
1234567891011121314151617181920
[[[RACSignal createSignal:^RACDisposable *(id subscriber) {&&&&&&&&&&&&&&&&[[RACScheduler mainThreadScheduler]afterDelay:3 schedule:^{&&&&&&&&&&&&&&&&&&&&&&&&[subscriber sendNext:@"rac"];&&&&&&&&&&&&[subscriber sendCompleted];&&&&&&&&}];&&&&&&&&&&&&&&&&return nil;&&&&}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]]&&&& subscribeNext:^(id x) {&&&&&&&& &&&&&&&& LxDBAnyVar(x);&&&& } error:^(NSError *error) {&&&&&&&& &&&&&&&& LxDBAnyVar(error);&&&& } completed:^{&&&&&&&& &&&&&&&& LxPrintAnything(completed);&&&& }];
上面代码的意思就是,我等待3秒中发送(afterDelay),但是我超时了(timeout)2秒钟才发送,所以这条信息发生错误,会走error的方法。 这种情况可以用在封装http client中,当然你可能遇到别的需求,也需要它。
take – skip
Objective-C
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(idsubscriber) {
[subscriber sendNext:@"rac1"];
[subscriber sendNext:@"rac2"];
[subscriber sendNext:@"rac3"];
[subscriber sendNext:@"rac4"];
[subscriber sendCompleted];
}]take:2];//Skip
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
123456789101112
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(idsubscriber) {&&&&&& [subscriber sendNext:@"rac1"];&&&&&& [subscriber sendNext:@"rac2"];&&&&&& [subscriber sendNext:@"rac3"];&&&&&& [subscriber sendNext:@"rac4"];&&&&&& [subscriber sendCompleted];&&&&&& return nil;&& }]take:2];//Skip&&& [signal subscribeNext:^(id x) {&&&&&& LxDBAnyVar(x);&& }];
比如说我们发送了很多次请求
take表示我们只取前两次
skip表示跳过前两次
takeLast表示倒数的前两次
takeUntil这个值比较特殊,他后面的参数是个信号,它的意思是,当takeUntil发送这个信号的时候,上面的发送信号就会停止发送。
接下来是几个block回调方法
takeWhileBlock BOOL值,意思是当返回YES的时候,订阅者才能收到信号
skipWhileBlock BOOL值,意思是当返回YES的时候,订阅者就会跳过信号,NO的时候才接受
skipUntilBlock BOOL值,意思是 返回NO的时候,不会收到消息, 直到返回YES的时候才开始收消息。
即时搜索优化 (throttle,distinctUntilChanged,ignore)
Objective-C
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
[self.view addSubview:textField];
@weakify(self);
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
//throttle 后面是个时间 表示rac_textSignal发送消息,0.3秒内没有再次发送就会相应,若是0.3内又发送消息了,便会在新的信息处重新计时
//distinctUntilChanged 表示两个消息相同的时候,只会发送一个请求
//ignore 表示如果消息和ignore后面的消息相同,则会忽略掉这条消息,不让其发送
[[[[[[textField.rac_textSignal throttle:0.3] distinctUntilChanged] ignore:@""] map:^id(id value) {
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
network request
[subscriber sendNext:value];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
cancel request
}]switchToLatest] subscribeNext:^(id x) {
LxDBAnyVar(x);
1234567891011121314151617181920212223242526272829303132
UITextField * textField = [[UITextField alloc]init];&& textField.backgroundColor = [UIColor cyanColor];&& [self.view addSubview:textField];&& && @weakify(self);&& && [textField mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&& &&&&&& @strongify(self);&&&&&& make.size.mas_equalTo(CGSizeMake(180, 40));&&&&&& make.center.equalTo(self.view);&& }];&& //throttle 后面是个时间 表示rac_textSignal发送消息,0.3秒内没有再次发送就会相应,若是0.3内又发送消息了,便会在新的信息处重新计时&& //distinctUntilChanged 表示两个消息相同的时候,只会发送一个请求&& //ignore 表示如果消息和ignore后面的消息相同,则会忽略掉这条消息,不让其发送&& [[[[[[textField.rac_textSignal throttle:0.3] distinctUntilChanged] ignore:@""] map:^id(id value) {&&&&&& &&&&&& return [RACSignal createSignal:^RACDisposable *(id subscriber) {&&&&&&&&&& &&&&&&&&&& //&&network request&&&&&&&&&& [subscriber sendNext:value];&&&&&&&&&& [subscriber sendCompleted];&&&&&&&&&& &&&&&&&&&& return [RACDisposable disposableWithBlock:^{&&&&&&&&&&&&&& &&&&&&&&&&&&&& //&&cancel request&&&&&&&&&& }];&&&&&& }];&& }]switchToLatest] subscribeNext:^(id x) {&&&&&& &&&&&& LxDBAnyVar(x);&& }];
以上代码,是用textField模拟一个即时搜索优化的功能,其中参数如下:
throttle 后面是个时间 表示rac_textSignal发送消息,0.3秒内没有再次发送就会相应,若是0.3内又发送消息了,便会在新的信息处重新计时
distinctUntilChanged 表示两个消息相同的时候,只会发送一个请求
ignore 表示如果消息和ignore后面的消息相同,则会忽略掉这条消息,不让其发送
这样做,是不是给服务器减小了很多的压力,更是节省了我们大量的代码。 其中我们用map建立了一个新的信号,我们知道textField的改变是一个信号, map就是在这个信号上,又加了一个信号,即signal of signals。
订阅者所打印的消息x则是,map发出的信号。我们可以再map中发送新的信号,以及取消信号disposable.
当我们用map发送信号的时候,我们则需要使用 switchToLatest这个参数来获取最后一个信号,也就是我们最后所打印的x,就是map最后发错的这个信号。
Objective-C
[[[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
}]delay:1]repeat]take:3] subscribeNext:^(id x) {
LxDBAnyVar(x);
} completed:^{
LxPrintAnything(completed);
12345678910111213
[[[[[RACSignal createSignal:^RACDisposable *(id subscriber) {&&&&&& &&&&&& [subscriber sendNext:@"rac"];&&&&&& [subscriber sendCompleted];&&&&&& &&&&&& return nil;&& }]delay:1]repeat]take:3] subscribeNext:^(id x) {&&&&&& &&&&&& LxDBAnyVar(x);&& } completed:^{&&&&&& &&&&&& LxPrintAnything(completed);&& }];
repeat,顾名思义,就是重复发送这条消息,当我们在后面添加了delay和take的时候,意思就是每隔1秒发送一次这条消息,发送3次后停止。
merge – concat – zipWith
Objective-C
RACSignal * signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
LxPrintAnything(a);
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable *(idsubscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
LxPrintAnything(b);
[subscriber sendNext:@"b"];
[subscriber sendCompleted];
[[RACSignal merge:@[signalA, signalB]]subscribeNext:^(id x) {
LxDBAnyVar(x);
1234567891011121314151617181920212223242526
RACSignal * signalA = [RACSignal createSignal:^RACDisposable *(idsubscriber) {&&&&&& &&&&&& dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{&&&&&&&&&& LxPrintAnything(a);&&&&&&&&&& [subscriber sendNext:@"a"];&&&&&&&&&& [subscriber sendCompleted];&&&&&& });&&&&&& &&&&&& return nil;&& }];&& && RACSignal * signalB = [RACSignal createSignal:^RACDisposable *(idsubscriber) {&&&&&& &&&&&& dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{&&&&&&&&&& LxPrintAnything(b);&&&&&&&&&& [subscriber sendNext:@"b"];&&&&&&&&&& [subscriber sendCompleted];&&&&&& });&&&&&& &&&&&& return nil;&& }];&& && [[RACSignal merge:@[signalA, signalB]]subscribeNext:^(id x) {&&&&&& &&&&&& LxDBAnyVar(x);&& }];
我们创建了两个请求,A和B,用GCD的方法A延迟两秒钟,B延迟了3秒钟,我们用merge方法合并了A和B,打印结果为
Objective-C
?__23-[ViewController merge]_block_invoke_2 + 66? a
?__23-[ViewController merge]_block_invoke29 + 87? x = a
?__23-[ViewController merge]_block_invoke_215 + 77? b
?__23-[ViewController merge]_block_invoke29 + 87? x = b
?__23-[ViewController merge]_block_invoke_2 + 66? a?__23-[ViewController merge]_block_invoke29 + 87? x = a?__23-[ViewController merge]_block_invoke_215 + 77? b?__23-[ViewController merge]_block_invoke29 + 87? x = b
也就是A和B不管谁发送都会打印x,简单的说就是A和B的打印方法用的是同一个。他们之间关系是独立的,如果A发送失败,B依然会执行。
当我们用concat方法链接A和B之后,意思就是当A执行完了之后才会执行B,他们之间是依赖的关系,如果A发送失败,B也不会执行。
请注意合并(merge)和链接(concat)的区别。
zipWith,当用zipWith链接A和B的时候,只有在A.B每隔都至少发送过一次消息的时候才会执行zipWith的方法,它的返回值是一个集合,也就是数组,同时包含了A和B的打印结果。
zipWith的写法等同于 :
Objective-C
[[RACSignal combineLatestWith:@[signalA, signalB]subscribeNext:^(id x) {
LxDBAnyVar(x);
[[RACSignal combineLatestWith:@[signalA, signalB]subscribeNext:^(id x) {&&&&&&&&&&&&&&&&LxDBAnyVar(x);&&&&}];
Objective-C
[[RACSignal combineLatest:@[signalA, signalB]]subscribeNext:^(id x) {
LxDBAnyVar(x);
[[RACSignal combineLatest:@[signalA, signalB]]subscribeNext:^(id x) {&&&&&&&&&&&&&&&&LxDBAnyVar(x);&&&&}];
但是使用combineLatest,可以再后面添加更多的信号.
Objective-C
//button setBackgroundColor:forState:
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:button];
@weakify(self);
[button mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
RAC(button, backgroundColor) = [RACObserve(button, selected) map:^UIColor *(NSNumber * selected) {
return [selected boolValue] ? [UIColor redColor] : [UIColor greenColor];
[[button rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(UIButton * btn) {
btn.selected = !btn.
1234567891011121314151617181920212223
//button setBackgroundColor:forState:&&&&&&&&UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];&&&&[self.view addSubview:button];&&&&&&&&@weakify(self);&&&&&&&&[button mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&&&&&&&&&&&&@strongify(self);&&&&&&&&make.size.mas_equalTo(CGSizeMake(180, 40));&&&&&&&&make.center.equalTo(self.view);&&&&}];&&&&&&&&RAC(button, backgroundColor) = [RACObserve(button, selected) map:^UIColor *(NSNumber * selected) {&&&&&&&&&&&&&&&&return [selected boolValue] ? [UIColor redColor] : [UIColor greenColor];&&&&}];&&&&&&&&[[button rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(UIButton * btn) {&&&&&&&&&&&&&&&&btn.selected = !btn.selected;&&&&}];
比如Btn的设置背景颜色的属性,OC中并没有button setBackgroundColor:forState:这种方法,我们不能直接设置其选中后的颜色。在RAC中,则可以很简单的改变BTN的背景颜色。不得不说RAC的简单和强大。
做一个秒表
Objective-C
UILabel * label = ({
UILabel * label = [[UILabel alloc]init];
label.backgroundColor = [UIColor cyanColor];
[self.view addSubview:label];
@weakify(self);
[label mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.size.mas_equalTo(CGSizeMake(240, 40));
make.center.equalTo(self.view);
RAC(label, text) = [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] map:^NSString *(NSDate * date) {
return date.
12345678910111213141516171819202122
UILabel * label = ({&&&&&&&&&&&& UILabel * label = [[UILabel alloc]init];&&&&&& label.backgroundColor = [UIColor cyanColor];&&&&&& label;&& });&& [self.view addSubview:label];&& && @weakify(self);&& && [label mas_makeConstraints:^(MASConstraintMaker *make) {&&&&&& @strongify(self);&&&&&& &&&&&& make.size.mas_equalTo(CGSizeMake(240, 40));&&&&&& make.center.equalTo(self.view);&&&&&& && }];&& && RAC(label, text) = [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] map:^NSString *(NSDate * date) {&&&&&& &&&&&& return date.description;&& }];
只有这么多代码,我们便可以完美的做一个秒表,是否很cool?
当我们大量使用RAC写代码的时候,会把一个个事件封装成一个个信号,通过触发信号,订阅这个信号来返回各种信息。RAC使我们的代码耦合性根底,聚合性更高。
若有不懂得地方可以留言,若有写错的地方,请及时与我联系,可以留言或者Email等。
文本所用的Demo,下载地址 .

我要回帖

更多关于 activity回调方法 的文章

 

随机推荐