博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ReactiveCocoa Introduction(1/2)
阅读量:6168 次
发布时间:2019-06-21

本文共 4269 字,大约阅读时间需要 14 分钟。

ReactiveCocoa Tutorial – 的学习笔记

先放一下,以后再研究。

iOS开发目前所用的事件(Events)以及对应的响应模型:target-actions, delegates, KVO, callbacks 等等,各不一样。

ReactiveCocoa则定义了一个事件的标准接口,使得它们更方便地串联、过滤以及组合。使用如下概念

a)Functional Programming(将函数提升到first-class地位,可以把函数作为传递的参数)

b)Reactive Programming 专注于数据流的传播和改变

所以Reactive Programming也叫Functional Reactive Programming(FRP) framework

再来一个概念, fluent interface,  类似于连续赋值的的method cascading/method chaining

c++的例子()如下, 每个成员函数都返回this的引用的基础上,最终使用接口的代码可以写成如下形式:

// Fluent usage int main(int argc, char **argv) {     FluentGlutApp(argc, argv)         .withDoubleBuffer().withRGBA().withAlpha().withDepth()         .at(200, 200).across(500, 500)         .named("My OpenGL/GLUT App")         .create(); }

(Objective-C这样连续调用,带来的不好看的一面是会在最前面累计无数"[")

以上具体概念可查阅wiki站,以下为教学内容,本次实例是将一个登录验证界面由传统的改为Reactive的

1. rac_textSignal 生成一个RACSignal 作为起点向它们的subscriber发送一系列事件,分类为三种: next, error, completed.

比如下面的subscribeNext 即是next事件。这句完成的动作是,usernameTextField的内容一旦被改变,即调用subscribeNext:注册的block,参数为textField.text

[self.usernameTextField.rac_textSignal subscribeNext:^(id x) {  NSLog(@"%@", x);}];

2.  filter: 来支持条件过滤

[[self.usernameTextField.rac_textSignal  filter:^BOOL(id value) {    NSString *text = value;    return text.length > 3;  }]  subscribeNext:^(id x) {    NSLog(@"%@", x);  }];

3. map: 来转义(否则每次传出来的都是同一个类型, 这个例子里是NSString*)

4. 用RAC(id, property)创建一个RACSignal的例子, validPasswordSignal参考上面。到这步,实现了输入字母够长则改变输入框背景颜色的功能。

RAC(self.passwordTextField, backgroundColor) =  [validPasswordSignal    map:^id(NSNumber *passwordValid) {      return [passwordValid boolValue] ? [UIColor clearColor] : [UIColor yellowColor];    }];

5. 合并信号combineLatest:, 用户名跟密码都合法了才能进行下一步操作(显示登录摁钮)

RACSignal *signUpActiveSignal =  [RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal]                    reduce:^id(NSNumber *usernameValid, NSNumber *passwordValid) {                      return @([usernameValid boolValue] && [passwordValid boolValue]);                    }];

6. 对于button的改造,准备登录

[[self.signInButton   rac_signalForControlEvents:UIControlEventTouchUpInside]   subscribeNext:^(id x) {     NSLog(@"button clicked");   }];

7. 改造一个dummy service(判断输入是否合法,通过则进入下一屏) 于是

-(RACSignal *)signInSignal {  return [RACSignal createSignal:^RACDisposable *(id
subscriber) { [self.signInService signInWithUsername:self.usernameTextField.text password:self.passwordTextField.text complete:^(BOOL success) { [subscriber sendNext:@(success)]; [subscriber sendCompleted]; }]; return nil; }];}

createSignal丢进来的是这样一个东西(block): (RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe

它是一个block, 返回值是RACDisposable *(大概是最后回收内存等清理工作?), block的参数是实现了RACSubscriber protocol的NSObject*

所以上面代码倒数第三行需要return nil, nil表示不需要清理。block内部,执行完判断后,给subscriber发送next 跟completed 事件。

8. signal of signals

参考下面的代码,如果不是flattenMap: 而是用map:, 运行时出错,丢出来的result: x是RACDynamicSignal

不是期待的@(success)合成的0或者1。 改完后,就可以在subscribeNext的block中根据结果做对应的操作了。

[[[self.signInButton   rac_signalForControlEvents:UIControlEventTouchUpInside]   flattenMap:^id(id x) { // x = signButton     return [self signInSignal];   }]   subscribeNext:^(id x) { // x = the signal if not flatternMap     NSLog(@"Sign in result: %@", x);   }];

9. 副作用/side effect

很细心的一个细节: 用户摁了signin button后必须disable掉这个button防止重复摁(其实是另一个细节带来的,为了防止暴力测试,验证过程中会delay2s出结果,在这个过程中,需要阻止多次sign in请求)。 从signal的角度看,这个要求是side effect, 它并不改变事件本身。

所以引入 doNext: , 最后代码是这样的:

[[[[self.signInButton   rac_signalForControlEvents:UIControlEventTouchUpInside]   doNext:^(id x) {     self.signInButton.enabled = NO;     self.signInFailureText.hidden = YES;   }]   flattenMap:^id(id x) {     return [self signInSignal];   }]   subscribeNext:^(NSNumber *signedIn) {     self.signInButton.enabled = YES;     BOOL success = [signedIn boolValue];     self.signInFailureText.hidden = success;     if (success) {       [self performSegueWithIdentifier:@"signInSuccess" sender:self];     }   }];

 

结论是ReactiveCocoa的代码逻辑性非常强,什么条件触发什么动作一目了然,避免了维护一堆记录状态的变量。确实炫。类似的入门描述还可以参考

http://www.teehanlax.com/blog/reactivecocoa/

http://www.teehanlax.com/blog/getting-started-with-reactivecocoa/

这个教程的第二部分,是描述另外两种事件类型: error跟completed, 以及throttling, threading,  continuations的,暂时感觉距离目前代码有点遥远,不能直接利用,先搁置吧。

2014.04.11

转载于:https://www.cnblogs.com/kurk/p/3658952.html

你可能感兴趣的文章
windows批处理 打开exe后关闭cmd
查看>>
Flask开发系列之快速入门
查看>>
公共语言运行时支持(/clr)
查看>>
spring集成shiro登陆流程(上)
查看>>
android:configChanges属性在不同版本SDK下需要注意的事项
查看>>
邻接表理解
查看>>
javascript-继承之jquery
查看>>
深入理解 KVC\KVO 实现机制 — KVC
查看>>
[转载]android开发手册
查看>>
PHPCMS列表页伪静态
查看>>
“System.IO.FileNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生
查看>>
SDUT 3002-素数间隙(素数筛+暴力)
查看>>
用php读取xml数据
查看>>
闽江学院软件学院2015级学生职业人物访谈
查看>>
npm教程_脚手架原理以及bootstrap引入
查看>>
琪露诺
查看>>
workqueue原理和分析(转)
查看>>
实现一些字符串操作标准库函数、解决一些字符串问题
查看>>
高级Unix命令
查看>>
解析AS3代码规范
查看>>