RAC 不是万能的

栏目: 数据库 · 发布时间: 5年前

内容简介:有句话说的好,“RP 不是万能的,没有 RP 却是万万不能的”。在 iOS 开发中,RP(响应式编程) 用得越来越多,其中我们最常用的响应式开发框架就是 ReactiveCocoa(俗称 RAC)。无可否认,RAC 的功能确实非常强大,可以用它完美替代 KVO、delegate、通知、UI 事件处理机制、定时器等一切对象通信机制,以至于很多同学把 RAC 当成了万应灵药。那么 RAC 是万能的吗?程序员可以在任何地方使用它吗?答案当然是不。与此相反,RAC 一旦使用不当,它就会变成致命的毒药。接下来,我们将

有句话说的好,“RP 不是万能的,没有 RP 却是万万不能的”。在 iOS 开发中,RP(响应式编程) 用得越来越多,其中我们最常用的响应式开发框架就是 ReactiveCocoa(俗称 RAC)。无可否认,RAC 的功能确实非常强大,可以用它完美替代 KVO、delegate、通知、UI 事件处理机制、定时器等一切对象通信机制,以至于很多同学把 RAC 当成了万应灵药。

那么 RAC 是万能的吗?程序员可以在任何地方使用它吗?

答案当然是不。与此相反,RAC 一旦使用不当,它就会变成致命的毒药。接下来,我们将列举两个 RAC 不适用的例子。

rac_textSignal 对委托模型的破坏

rac_textSignal 是对 UITextField/UITextView 委托模型的替代,但这种替代是破坏性的。

也就是说,一旦你使用了 rac_textSignal,你将无法在 UITextField/UITextView 上使用委托模式。

原因就在于:

  1. rac_textSignal 信号在运行时中使用了 UITextField/UITextView 的委托模型,由于委托模型是单对单模式,所以原来的委托机制就被 rac_textSignal 阻断了,此时再用 textFieldDidChange/textViewDidChange 就不再生效了。如果一定要使用 UITextField/UITextView 的委托机制,就不能使用 rac_textSignal。或者将 rac_textSignal 替换成 KVO 信号(即 RACObserve),但这会导致第二种情况发生。
  2. rac_textSignal 信号不仅仅使用了 delegate,也覆盖了 KVO。也就是说,rac_textSignal 是 delegate+KVO 全覆盖的,不仅仅会在委托事件中触发信号,而且在 text 属性被代码修改时触发信号。前者是由用户按键产生的,后者是由 程序员 用代码修改 text 属性产生的。也就是说,rac_textSignal 不仅能监听用户按键,也能监听 text 属性的改变。

这就导致了一种潜在的问题。考虑这样一种场景。如果你需要限制 TextField 中用户能够输入的字数。通常我们会在 rac_textSignal 订阅块中,对输入的字符数进行判断,一旦它超过限制,我们就对字符串进行截断。这很简单,简单到可能只需要一行代码。但这样就会在订阅块中直接修改到 textfield 的 text 属性,由于代码修改 text 属性导致 textfiel 的 KVO 事件发生,那么又会触发 rac_textSingal 信号。如果你没有对修改 text 的语句进行条件判断,那么这就会导致死循环发生,app 崩溃。

如果在中文输入法打开的情况下,还会导致重复输入候选词条的情况。比如你输入"df",文本框中会出现多次重复的"dfdfdfdf"。

在调试模式下,rac_textSignal 还会导致 delete 字符自动重复的情况。即按一下 delete 键,发送两个 delete 字符。

cell 复用的问题

rac_textSignal 用在复用的 cell 时问题更大。

有时候问为了监听 cell 中 textfield 的文字改变,我们会在 cellForItemAtIndex 方法中使用这样的代码:

TextFieldCell* cell = [self.collectionContext 	dequeueReusableCellOfClass:TextFieldCell.class 	forSectionController:self atIndex:index];
            
cell.tfText.text= dev.management;
[[[cell.tfText rac\_textSignal] skip:1] 	subscribeNext:^(NSString * _Nullable x) {
		self.device.management = x;
}];

这样的问题在于,由于 cell 是复用的,当 cell 复用时,rac_textSignal 会被重复订阅。当你从缓存中复用一个 cell 时,这个 cell 的 rac_textSignal 很可能已经被订阅过了。这个时候你再次订阅 rac_textSignal 信号,就重复订阅了。导致用户在当前 cell 的文本框中输入值后,重复调用订阅块,即可能改变了多个值。比如,明明用户在输入姓名时输入的是 a,但莫名其妙不仅仅是用户的姓名被修改为 a 了,用户的邮箱、手机号都被修改为 a 了。

这个问题一般很难排查,因为 cell 很可能不被复用,或者什么时候会复用一个 cell 我们也无从知道,cell 的复用机制位于 UITableView/UICollectionView 的“黑盒子”中。

更糟糕的是,RAC 本身无法解决这个问题。你可能想在订阅一个 rac_textSignal 信号前将同一个 textfield 上的 rac_textSignal 信号停止,或者取消其它订阅者,但 RAC 本身没有提供这样的机制。只有在订阅时保持住一个 RACDisposable,然后在每次订阅前调用 dispose 方法。

// 有多少个 textfield 就要有多少个 RACDisposal 属性
@property (strong, nonatomic) RACDisposable* disposable1;
@property (strong, nonatomic) RACDisposable* disposable2;
@property (strong, nonatomic) RACDisposable* disposable3;

... ...

// 在订阅之前 dispose,有多少个 textfield 就要 dispose 多少次
	[_disposable1 dispose];
	_disposable1 = [[cell.tfText rac\_textSignal] subscribeNext:^(NSString * _Nullable x) {
                self.device.management = x;
            }];
... ...

这个方式和另外一种方式一样,假设每个 cell 上都有一个 textfield,那么有多少个 cell 就得声明多少个属性,如果 cell 的个数不固定,这种方案不是很美妙啊。

另外一种方式就是保持住每一个 cell,即有多少 cell 就声明多少属性,每个 cell 属性都使用懒加载的方式,即只有在第一次初始化时订阅 rac_textSignal,这样就不会重复订阅。

当然最完美的解决办法就是不使用 rac_textSignal,而是用 UITextFieldDelegate,同时通过 index 来识别这是哪个 textfield:

cell.tfText.tag = index;
cell.tfText.delegate = self;

......

-(void)textFieldDidEndEditing:(UITextField *)textField{
    switch (textField.tag) {
        case 5:{// 管理部门
            _device.management = textField.text;
            break;
        }
        case 6:{// 管理人员
            _device.managementUser = textField.text;
            break;
        }
        case 7:{// 负责人员
            _device.liableUser = textField.text;
            break;
        }
        default:
            break;
    }
}

以上所述就是小编给大家介绍的《RAC 不是万能的》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

乐在C语言

乐在C语言

蔡明志 / 2013-1 / 39.00元

《乐在C语言》由蔡明志所著,本书内容的撰写上,以浅显易懂的文字,并搭配简短的范例程序,以及通俗幽默的漫画,讲述每一章的主题,真正做到了繁杂的问题通俗化,通俗化了的问题实例化,使读者得到事半功倍的学习效果。《乐在C语言》基本包括了C语言编程的全部内容,如变量、函数、指针、结构体、文件等。每一章都有上机实习,这些题目是从范例程序中加以演变的,以便读者能举一反三,达到学以致用。 《乐在C语......一起来看看 《乐在C语言》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

MD5 加密
MD5 加密

MD5 加密工具