ReactiveCocoa / RxSwift 笔记一

原创:转载请注明出处

ReactiveCocoa / RxSwift

Native app有很大一部分的时间是在等待事件发生,然后响应事件,比如

1.等待网络请求完成,

2.等待用户的操作,

3.等待某些状态值的改变等等,

等这些事件发生后,再做进一步处理

但是这些等待和响应,并没有一个统一的处理方式。Delegate, Notification, Block, KVO, 常常会不知道该用哪个最合适。有时需要chain或者compose某几个事件,就需要多个状态变量,而状态变量一多,复杂度也就上来了。为了解决这些问题,Github的工程师们开发了ReactiveCocoa。

概念

插座:Signal   ->  插座负责去获取并提供电   <—>  Observable

插头:Subscriber  -> 插头负责使用电       <—> Observer

用途

Signal 获取到数据后,会调用Subscriber的sendNext, sendComplete, sendError方法来传送数据给Subscriber,

<>

RxSwift  : onNext   onComplete   onError

Subscriber 自然也有方法来获取传过来的数据,如:[signal subscribeNext:error:completed]。这样只要没有sendComplete和sendError,新的值就会通过sendNext源源不断地传送过来

<>

RxSwift:

reloadDataItem.rx_tap

.subscribeNext { [unowned self] in

self.initialization()

}.addDisposableTo(disposeBag)

RAC 是基于KVO的

原理:

RACObserve使用了KVO来监听property的变化,只要username被自己或外部改变,block就会被执行。但不是所有的property都可以被RACObserve,该property必须支持KVO,比如NSURLCache的currentDiskUsage就不能被RACObserve.

灵活性:

Signal是很灵活的,它可以被修改(map),过滤(filter),叠加(combine),串联(chain),这有助于应对更加复杂的情况,

RAC(self.logInButton, enabled) = [RACSignal

combineLatest:@[

self.usernameTextField.rac_textSignal,

self.passwordTextField.rac_textSignal,

RACObserve(LoginManager.sharedManager, loggingIn),

RACObserve(self, loggedIn)

] reduce:^(NSString *username, NSString *password, NSNumber *loggingIn, NSNumber *loggedIn) {

return @(username.length > 0 && password.length > 0 && !loggingIn.boolValue && !loggedIn.boolValue);         }];

1.只要usernameTextField的值有变化,这个值就会被返回(sendNext)。

2.combineLatest需要每个signal至少都有过一次sendNext。

3.reduce的作用是根据接收到的值,再返回一个新的值,这里是@(YES)和@(NO),必须是object。

<>

RxSwift:

Observable.combineLatest(calendarRequest, scheduleRequest, calendarVC.rx_didScrollToMonth) {

(scheduleList: $0, schedule: $1, didScroll:$2)

}

.onAlertError()

.subscribe(

onNext: { [unowned self] x in

//self.updateData(x.scheduleList, schedule: x.schedule, noticeList: nil)

},

onError: { [unowned self] error in

//

},

onCompleted: {

//

}

).addDisposableTo(self.disposeBag)

Side Effect

还是上面那段代码,如果有多个subscriber,那么signal就会又一次被触发,控制台里会输出两次triggered。这或许是你想要的,或许不是。如果要避免这种情况的发生,可以使用 replay 方法,它的作用是保证signal只被触发一次,然后把sendNext的value存起来,下次再有新的subscriber时,直接发送缓存的数据。

Cocoa Categories

UIView Categories

1. [[alertView rac_buttonClickedSignal] subscribeNext:^(NSNumber *indexNumber) {

//toDo

}];

RAC给UITableViewCell提供了一个方法:rac_prepareForReuseSignal,它的作用是当Cell即将要被重用时,告诉Cell。想象Cell上有多个button,Cell在初始化时给每个button都addTarget:action:forControlEvents,被重用时需要先移除这些target,下面这段代码就可以很方便地解决这个问题:

  1. [[[self.cancelButton
  2. rac_signalForControlEvents:UIControlEventTouchUpInside]
  3. takeUntil:self.rac_prepareForReuseSignal]
  4. subscribeNext:^(UIButton *x) {
  5. // do other things
  6. }];

rac_command,就是当button被按下时会执行的一个命令,命令被执行完后可以返回一个signal,有了signal就有了灵活性。比如点击投票按钮,先判断一下有没有登录,如果有就发HTTP请求,没有就弹出登陆框,可以这么实现。

NotificationCenter Category

NSNotificationCenter, 默认情况下NSNotificationCenter使用Target-Action方式来处理Notification,这样就需要另外定义一个方法,这就涉及到编程领域的两大难题之一:起名字。有了RAC,就有Signal,有了Signal就可以subscribe,于是NotificationCenter就可以这么来处理,还不用担心移除observer的问题。

  1. [[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"MyNotification" object:nil] subscribeNext:^(NSNotification *notification) {
  2. NSLog(@"Notification Received");
  3. }];

NSObject+RACDeallocating.h

顾名思义就是在一个objectdealloc被触发时,执行的一段代码。

  1. NSArray *array = @[@"foo"];
  2. [[array rac_willDeallocSignal] subscribeCompleted:^{
  3. NSLog(@"oops, i will be gone");
  4. }];
  5. array = nil;

NSObject+RACSelectorSignal.h

这个category有rac_signalForSelector:和rac_signalForSelector:fromProtocol: 这两个方法。先来看前一个,它的意思是当某个selector被调用时,再执行一段指定的代码,相当于hook。比如点击某个按钮后,记个日志。后者表示该selector实现了某个协议,所以可以用它来实现Delegate。

MVVM

MVVM跟MVC最大的区别是多了个ViewModel,它直接与View绑定,而且对View一无所知。拿做菜打比方的话,ViewModel就是调料,它不关心做的到底是什么菜。它可以扮演Model的职责,但其实它是Model的中介,这样当Model的API有变化,或者由本地存储变为远程API调用时,ViewModel的public API可以保持不变。

使用ViewModel的好处是,可以让Controller更加简单和轻便,而且ViewModel相对独立,也更加方便测试和重用。那Controller这时又该做哪些事呢?在MVVM体系中,Controller可以被看成View,所以它的主要工作是

处理布局、

动画、

接收系统事件、

展示UI。

MVVM还有一个很重要的概念是 data binding,view的呈现需要data,这个data就是由ViewModel提供的,将view的data与ViewModel的data绑定后,将来双方的数据只要一方有变化,另一方就能收到。这里有Github 开源的一个ViewModel Base Class。

其他

RAC在使用时有一些注意事项,可以参考官方的DesignGuildLines,这里简单说一下。

当一个signal被一个subscriber subscribe后,这个subscriber何时会被移除?答案是当subscriber被sendComplete或sendError时,或者手动调用[disposable dispose]。

当subscriber被dispose后,所有该subscriber相关的工作都会被停止或取消,如http请求,资源也会被释放。

Signal events是线性的,不会出现并发的情况,除非显示地指定Scheduler。所以-subscribeNext:error:completed:里的block不需要锁定或者synchronized等操作,其他的events会依次排队,直到block处理完成。

Errors有优先权,如果有多个signals被同时监听,只要其中一个signal sendError,那么error就会立刻被传送给subscriber,并导致signals终止执行。相当于Exception。

生成Signal时,最好指定Name, -setNameWithFormat: 方便调试。

block代码中不要阻塞。

时间: 2024-10-12 09:24:30

ReactiveCocoa / RxSwift 笔记一的相关文章

iOS开发ReactiveCocoa学习笔记(四)

ReactiveCocoa常见操作方法介绍: demo地址:https://github.com/SummerHH/ReactiveCocoa.git p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #008400 } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #008400; min-height: 13.0px }

iOS开发ReactiveCocoa学习笔记(二)

RAC 中常见的宏: 使用宏定义要单独导入 #import <RACEXTScope.h> 一. RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定 只要文本框文字改变,就会修改label的文字 RAC(self.labelView,text) = _textField.rac_textSignal; 二. RACObserve(self, name):监听某个对象的某个属性,返回的是信号. [RACObserve(self.view, cen

iOS开发ReactiveCocoa学习笔记(-)

学习 RAC 我们首先要了解 RAC 都有哪些类 RACSignal RACSubject RACSequence RACMulticastConnection RACCommand 在学习的时候写了一个小 demo 来分别介绍每个类的作用,gitHub 地址: https://github.com/SummerHH/ReactiveCocoa.git demo 的目录结构如下 RAC学习起来的特点 学习起来比较难 团队开发的时候需要谨慎使用 团队代码需要不断的评审,保证团队中所有人代码的风格一

ReactiveCocoa学习笔记

1. RACSignal使用步骤及底层实现 (1) 创建信号 (RACSignal底层实现:把didSubscribe保存到信号中,还不会触发.) createSignal的意义是,创建一个signal对象,并且把参数赋值给signal的名为didSubscribe的属性,这个block的参数是subscriber,返回RACDisposable. + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscr

高大上函数响应式编程框架ReactiveCocoa学习笔记1 简介

原创文章,转载请声明出处哈. ReactiveCocoa函数响应式编程 一.简介 ReactiveCocoa(其简称为RAC)是函数响应式编程框架.RAC具有函数式编程和响应式编程的特性.它主要吸取了.Net的 Reactive Extensions的设计和实现. 函数式编程 (Functional Programming) 函数式编程也可以写N篇,它是完全不同于OO的编程模式,这里主要讲一下这个框架使用到的函数式思想. 1) 高阶函数:在函数式编程中,把函数当参数来回传递,而这个,说成术语,我

ReactiveCocoa 学习笔记

1 // 2 // RootViewController.m 3 // SimpleWeather 4 // 5 // Created by TBXark on 15-4-17. 6 // Copyright (c) 2015年 Ryan Nystrom. All rights reserved. 7 // 8 9 #import "RootViewController.h" 10 #import <ReactiveCocoa.h> 11 #import <TSMes

ReactiveCocoa学习笔记--用法

1.监测UI变量的变化 return 后把值传递下去. 1.1.输出 [self.usernameTextField.rac_textSignal subscribeNext:^(id x){ NSLog(@"%@", x); }]; 1.2.过滤->输出 [[self.usernameTextField.rac_textSignal filter:^BOOL(NSString*text){ return text.length > 3; }] subscribeNext:

Event Loop、函数式编程、IO多路复用、事件驱动、响应式、

IO多路复用.事件驱动.响应式概念类似或者一样 就是很多网络连接(多路),共(复)用少数几个(甚至是一个)线程. 连接很多的时候,不能每个连接一个线程,会耗尽系统内存的.线程也不能阻塞在任何一个连接上,等新的数据来,这样就不能及时响应其他连接发来的数据了:也不能用非阻塞方式,轮询所有的连接,这会浪费掉大量CPU时间:只能告诉系统,我对哪些连接感兴趣,有消息来的时候,通知我处理. IO多路复用: 一种在后端网络编程中的一种技术 IO多路复用机制详解    服务器,并发,"事件驱动"的本质

小学生笔记之ReactiveCocoa入门

一.响应式编程范式FRP FRP,全称为Functional Reactive Programming,是一种响应变化的编程范式,最近几年比较火,大概的理解就像这样: 当a的值或者b的值发生变化时,c的值会自动响应a的值或b的值变化的信号,自动更正自己的值,类似这种编程思想就称为FRP. FRP提供了一种信号机制来实现这样的效果,通过信号来记录值的变化.信号可以被叠加.分割或合并.通过对信号的组合,就不需要去监听某个值或事件. 二.ReactiveCocoa介绍 ReactiveCocoa是gi