我们首先从一个双向绑定的例子开始。假设我们的
里有一个
和一个
, 我们希望在
输入时,
里面同步显示一样的内容。我们通过把
和
绑定到同一个
,也就是
的
属性上
来实现这一点。
当
变化时,
和
都会随之变化。而当
中的输入发生变化时,
也会发生变化。
和
发生了双向绑定,而
和
是单向绑定。
我们把上面的代码用
展开,看看到底发生了什么:
简化一下:
等等,1
| @(((void)(__objc_no && ((void)self.nameTextfield.text, __objc_no)), "text"))
|
这个是什么东西? 这个东西其实就等效于
,但是为什么要前面这一长串呢?这是为了在编译期防止你引用了错误的属性,比如你写了1
| @RAC(self.nameTextField, somethingNotexist)
|
,编译器就会给出提示说这个属性不存在。clever.
RAC
我们来看前半部分,也就是RAC的展开:
RAC宏第一个参数是target,也就是需要绑定的对象;第二个参数是keyPath, 也就是对象中需要绑定的属性名。RAC实际上是创建了一个RACSubscriptingAssignmentTrampoline对象,并调用其1
| setObject:forKeyedSubscript:
|
方法。
可见RAC的下标set操作对右边的信号调用了subscribeNext, 并在所有的next event中通过1
| object setValue:forKeyPath
|
修改属性的值。在这个例子里,也就相当于1
| [self.nameTextField setValue:x forKeyPath: @"text"]
|
RACObserve
RACObserve的展开:
rac_valuesForKeyPath:observer:调用了另一个方法:
这个方法创建了一个RACSignal, 这个Signal在keypath发生变化时会发出“通知”.
这个Signal由RACKVOTrampoline实现,RACKVOTrampoline封装了KVO,将在keypath发生变化时发送信号。
rac_textSignal
知道了
和
,接下来我们来看
的实现:
可见rac_textSignal监控UIControlEventEditingChanged | UIControlEventEditingDidBegin事件,subscriber将获得textfield.text
weakify 和strongify
RAC中常见的
和
展开如下:
为了看起来美观,用了一个
的hack,使得宏的前面可以用
,有点意思。
textView
前面
的
使用监控control events的方式来获取变化。但是
并没有这些event。所以RAC使用了delegate的方式来实现
的
。但是又有一个问题:如果想同时使用delegate怎么办呢?
delegate forwardInvocation
RACDelegateProxy会用forwardInvocation的方式发送给self.delegate
所以如果需要同时使用,先设置delegate,再使用rac_textSignal即可。
是RAC中一个重要的方法,它的作用简单来说就是勾住一个方法,当这个方法被调用时把所有的参数放在一个tuple里,当做信号发出来。因此,1
| RACUseDelegateProxy(self)
|
把
的
指向
,而1
| RACDelegateProxy signalForSelector:@selector(textViewDidChange:)
|
就可以捕捉所有原本调用
的方法,并发出
实例作为信号,并在
中获得其
属性。
参考
关于ReactiveCocoa:
http://cocoasamurai.blogspot.jp/2013/03/basic-mvvm-with-reactivecocoa.html
http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1