iOS-ReactiveCocoa学习笔记1

一篇关于RectiveCocoa的总结文档

百度搜索了一下RectiveCocoa,都是与MVVM关联在一起。

1·简述下MVVM

MVC:ModelViewViewController

MVVM:ModelViewView-Model

Model:容纳表现数据-模型对象信息的结构体,并在一个单独的管理类中维护的创建/管理模型的统一逻辑。

View:包含实际 UI 本身(不论是 UIView 代码, storyboard 和 xib), 任何视图特定的逻辑, 和对用户输入的反馈. 在 iOS 中这不仅需要 UIView 代码和那些文件, 还包括很多需由 UIViewController 处理的工作。

View-Model:

1、作为一个表现视图显示自身所需数据的静态模型;

2、收集, 解释和转换那些数据;

收集:网络请求,control控制的数值变更;

解释:赋值;

转换:viewmodel内的逻辑运算;

3、目的:让view(controller)的任务更清晰,就是展示view-Model提供的数据。

Summary:Model不变,view不变,增加View-Model分担ViewController的责任(每个view将有自己的view-model来约束)

其最终结果就是MVMCV

关于View-Model

不对视图控制器起作用,或通告其变化

关于ViewController

1、不再发起网络服务调用

2、不再管理数组(类似tableview的dataSource)

3、不再判断某些值是否有效

4、其实就是不再管text或者image是什么了

5、只管view-Model中的变化

Summary:将view-model与view关联,通过修改view model中的值的变更来修改view中的数值变化;ViewController就只能老老实实的管view-model的数值变更就好了。

2·ReactiveCocoa

解决View和View-Model关联的问题

举例

假设这是一个登陆页面,我要判断用户名是否合法,密码是否匹配,这些在MVC的情况下我都会在Controller中进行判断,是的话会怎么怎么样,不是的话会怎么怎么样。

而在MVVM和RectiveCocoa的帮助下,我们可以使用一个登陆的ViewModel,所有的判断和结果我可以写在ViewModel中。而在Controller中我只要1、关联用户名的text和viewmodel中的username,密码对应。2、就不用管TA了。

RectiveCocoa的学习

概念,一直是我不想去背却又不得不背的东西。

1、RACSignal:RAC的构造单元,代表我们最终收到的信息,(当你能将未来某事某刻接收到的消息具体表示出来,我们可以预先运用逻辑构建信息流,而不是等到事件发生)

简述:

1、信号是基本单位,也是写完代码会接收到的东西,因为是数据关联在view和view-model上,我们可以提前将需要展示出来的数据在viewmodel中处理了,再通过关联影响view的值的变化。而不是在controller中书写了。(个人理解,如有偏差,请各种指正)

2、信号会为了控制通过应用的信息流而获得所有这些异步方法(委托, 回调 block, 通知, KVO, target/action 事件观察, 等)并将它们统一到一个接口下.这只是直观理解. 不仅是这些, 因为信息会流过你的应用, 它还提供给你轻松转换/分解/合并/过滤信息的能力.

简述:中央集权制,信号中处理这些传值方式;并通过书写的逻辑达到预期的效果。

信号如何将ViewModel与View关联上

信号是一个发送一连串值的物体。需要在订阅者监听时信号才会发信息,信号会向订阅者发送0或多个带有数值的’next’事件,后面带有’complete’或’error’。

(信号类似于其他语言/工具包中的“promise”(1),但更强大,因为它不仅限于向它的订阅者一次只传递一个返回值. )

1、创建一个信号

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {

return nil;

}];

2、信号中添加订阅者接收到的东西

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id subscriber) {

//以下为新加

NSString *str=[NSString stringWithFormat:@"https://www.baidu.com"];

NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

NSURLRequest *request = [NSURLRequest requestWithURL:url];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]init];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

[subscriber sendNext:@""];

[subscriber sendCompleted];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[subscriber sendError:error];

}];

[operation start];

//end

return nil;

}];

3、RACObserve()

这个宏是 RAC 中对 KVO 中那些悲惨的 API 的替代。 你只需要传入对象和你想观察的那个对象某属性的 keypath.。给出这些参数后, RACObserve 会创建一个信号,一旦它有了订阅者,,它就立刻发送那个属性的当前值,并在发送那个属性在这之后的任何变化。

RACSignal *signal1 = RACObserve(self. personModel,name);

//这行代码的前提是你有一个personModel,personModel有一个name属性

这仅是提供用于创建信号的一个工具. 这里有几个立即可用的方式, 来从内置控制流机制中拉取信号:

RACSignal *controlUpdate = [_myButtonrac_signalForControlEvents:UIControlEventTouchUpInside];

// signals for UIControl events send the control event value (UITextField, UIButton, UISlider, etc)

// subscribeNext:^(UIButton *button) { NSLog(@"%@", button); // UIButton instance }

RACSignal *textChange = [_myTextFieldrac_textSignal];

// some special methods are provided for commonly needed control event values off certain controls

// subscribeNext:^(UITextField *textfield) { NSLog(@"%@", _textfield.text); // "Hello!" }

RACSignal *alertButtonClicked = [_myAlertViewrac_buttonClickedSignal];

// signals for some delegate methods send the delegate params as the value

// e.g. UIAlertView, UIActionSheet, UIImagePickerControl, etc

// (limited to methods that return void)

// subscribeNext:^(NSNumber *buttonIndex) { NSLog(@"%@", buttonIndex); // "1" }

RACSignal *viewAppeared = [self rac_signalForSelector:@selector(viewDidAppear:)];

// signals for arbitrary selectors that return void, send the method params as the value

// works for built in or your own methods

// subscribeNext:^(NSNumber *animated) { NSLog(@"viewDidAppear %@", animated); // "viewDidAppear 1" }

什么是订阅者?

简言之,订阅者就是一段代码,它等待信号给它发送一些值,然后订阅者就能处理这些值了. (它也可以作用于“complete”和“error”事件. )

简述:理解为block,信号等同block调用?

RACSignal *usernameValidSignal = RACObserve(self. personModel,name);

// update the local property when this value changes

[usernameValidSignal subscribeNext: ^(NSNumber *isValidUserName) {

self.isValidName = isValidUserName.boolValue;

}];

以上代码前提:controller 有一个personModel,有一个BOOL类型的isValidName,Model中有Number类型的isValidUserName

那问题来了,isValidName是BOOL为何我要传NSNumber类型的。

答:RAC 只处理对象, 而不处理像 BOOL 这样的原始值.。不过不用担心,RAC 通常会帮你这些转换。

RAC(self,isValidName) = RACObserve(self.personModel, isValidUserName);

//前面是target 后面是target下的@property

//用中文讲,就是self.personModel的isValidUserName变化了,self.isValidName也要跟着变了。

那问题来了,self.isValidName做什么用,判断吗?那不就又绕回来了?把controller以前做判断啊什么的逻辑交给viewmodel就好了,所以呢……

这样我们可以把RACObserve(self.personModel, isValidUserName);绑定在textchange的协议方法中,或是确定按钮的enable中,等等等等所有用这个值判断的位置上(选位置时注意,不要总想在controller中操作)。

多个订阅者, 副作用, 昂贵的操作

订阅信号链时要明白重要的一件事是每当一个新值通过信号链被发送出去时, 实际上会给每个订阅者都发送一次. 直到意识到这就我们而言是有意义的, 信号发出的值不存储在任何地方(除了 RAC 在内部实现中). 当信号需要发送一个新的值时, 它会遍历所有的订阅者并给每个订阅者发送那个值. (这是对信号链实际工作的简化说明, 但基本想法是对的)

这为什么重要?这意味着信号链某处存在的任何副作用, 任何影响应用世界的转变, 将会发生多次. 这对新接触 RAC 的用户来说是意想不到的. (这也违反了函数式构建的理念-数据输入, 数据输出).

一个做作的例子可能是: 信号链某处的信号在每次按钮被按下时更新 self 中的一个计数器属性. 如果信号链有多个订阅者, 计数器的增长将会比你想的还要多. 你需要努力从信号链中尽可能剔除副作用. 当副作用不可避免时, 你可以使用一些恰当的预防机制. 我将会在另一篇文章中探索.

简述:当存在多个订阅者的时候,就像一对多广播一样,只要是订阅者就会都遍历一次。在设计之初就应该规范,不管是针对子viewModel的分别控制,还是条件限制,等等,

除副作用之外, 我们需要注意带有昂贵操作和可变数据的信号链. 网络请求就是一个三者兼得的例子:

网络请求影响了应用的网络层(副作用).

网络请求为信号链引入了可变数据. (两个完全一样请求可能返回了不同的数据. )

网络请求反应慢啊.

假设我根据一个text,text作为参数,发起多个网络请求,我所要的结果在网络请求的结果中,那么多个订阅者如何处理这个返回结果,下一篇介绍RACCommand

额外:自行百度-mock、method swizzling

(1)promise的概念

ES6原生提供了Promise对象。

所谓Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的API,可供进一步处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容