UIButton使用RACCommand后setEnable方法失效的问题
2016-08-25 15:30
477 查看
问题描述
首先,我们知道RACCommand有如下初始化方法,可以传入enabledSignal,用于控制按钮的enable状态。- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock;
但有时我们想自己控制按钮的enable状态。这个时候就可能出现标题所说的问题。标题为了表达意思,并不准确。真正的问题是RACCommand内部调用setEnable方法,可能会覆盖你手动设置的UIButton状态。无论你在初始化RACommand时是否传入enabledSignal,RACCommand内部都会控制UIButton的enable/disable状态。我们在外部也调用setEnable方法设置enable状态,可能会冲突。
举个栗子
RACCommand *sendCodeCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { [sendCodeButton setEnabled:NO]; //TODO: Send code, count down and then setEnabled:YES return [RACSignal empty]; }]; sendCodeButton.rac_command = sendCodeCommand;
上面这段代码,我们的预期是点击发送验证码按钮之后disable掉按钮,进行倒计时,倒计时结束重新enable按钮。事实上,我们点击按钮之后,按钮并没有被disable掉。
简单解决方案
放弃手动控制按钮的enable状态,在初始化RACCommand时候传入enabledSignal,让RACCommand统一负责。不过使用Signal控制enable状态需要额外的转换操作,要费些事。RACCommand内部是如何控制UIButton enable状态的
如果我们知道RACCommand内部是如何控制enable状态的,我们就可以避免冲突。我们在UIButton+RACCommandSupport.m可以找到下面这条语句:
disposable = [command.enabled setKeyPath:@keypath(self.enabled) onObject:self];
这条语句将UIButton的enable属性与RACCommand中的enabled信号绑定起来了,那么我们就来看看RACCommand中的enabled信号的如何创建的,如何变化的。
我们在RACCommand.m中找到下面这段代码:
if (enabledSignal == nil) { enabledSignal = [RACSignal return:@YES]; } else { enabledSignal = [[[enabledSignal startWith:@YES] takeUntil:self.rac_willDeallocSignal] replayLast]; } _immediateEnabled = [[RACSignal combineLatest:@[ enabledSignal, moreExecutionsAllowed ]] and]; _enabled = [[[[[self.immediateEnabled take:1] concat:[[self.immediateEnabled skip:1] deliverOn:RACScheduler.mainThreadScheduler]] distinctUntilChanged] replayLast] setNameWithFormat:@"%@ -enabled", self];
可以看到enabled信号受我们传入的enabled信号(不传,默认为
[RACSignal return:@YES])和内部的moreExecutionsAllowed信号影响。它们进行与操作。再看看moreExecutionsAllowed信号的定义。
RACSignal *immediateExecuting = [RACObserve(self, activeExecutionSignals) map:^(NSArray *activeSignals) { return @(activeSignals.count > 0); }]; RACSignal *moreExecutionsAllowed = [RACSignal if:RACObserve(self, allowsConcurrentExecution) then:[RACSignal return:@YES] else:[immediateExecuting not]];
moreExecutionsAllowed信号受allowsConcurrentExecution属性和immediateExecuting信号影响。如果允许并发,moreExecutionsAllowed发出的是@YES;如果不允许并发,目前有未完成任务,发出@NO,否则发出@YES。这里的任务完成是指signalBlock创建出来的Signal已经complete了,signalBlock是在
- (id)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock方法中传入的。
回到我们上面举的栗子,在signalBlock中我们disable了sendCodeButton,但是返回了
[RACSignal empty],
[RACSignal empty]会立即complete,activeExecutionSignals会remove掉这个signal,然后activeSignals.count变为0,immediateExecuting发出@NO,moreExecutionsAllowed发出@YES,最终enabled信号发出@YES,sendCodeButton被enable。我们刚才设置的状态被冲掉了。
相关文章推荐
- 关于使用matplotlib-legend方法失效问题
- Bootstrap框架使用iframe及jQuery中load方法导致js失效问题
- 使用jquery的load方法设计动态加载,并解决被加载页面JavaScript失效问题
- 生成动态库so的方法|解决NDK r5b引用静态库失效的问题|在NDK的Nactive代码中使用Android Log的方法|生成Native java头文件
- 使用jQuery的load方法设计动态加载及解决被加载页面js失效问题
- oncontextmenu简单使用方法,以及在js函数中失效的问题
- 使用Ajax时处理用户session失效问题的解决方法
- 使用jquery的load方法设计动态加载,并解决被加载页面JavaScript失效问题
- [ChneChen的随笔][管理之道]什么才是我们需要的解决问题的方法(从如何限制公司电脑使用U盘解决之道谈起)
- 第一次使用jdbc连接postgre数据库碰到的问题及解决方法
- Struts使用中ActionForm get set方法的小问题
- 关于ISA2004内网卡网线拔插造成ISA代理失效问题的一种解决方法(下列错误而失败:0x80072
- 使用Axis部署Web服务时的常见问题及其解决方法(转)
- 使用webservice解决多系统登陆问题(方法一)
- 关于使用asp.net调试器出现的问题及相关解决方法
- 使用ActionlessForm.cs重写Form后使得验证控件失效的解决方法
- 关于在使用Exchange2003系统时无法向sina,yahoo,hotmail等邮箱发送邮件问题的解决方法
- TOAD8.3.5 在SQL Editor 中编辑是Backspace键 Delete 键删除失效的问题解决方法
- Firefox 使用常见问题和解决方法
- 使用Apache Axis部署 Web服务时的常见问题及其解决方法(转)