我正在玩RAC,特别是Colin Eberhardt的Twitter搜索example,并遇到了我无法向自己解释的崩溃。
这是我创建的sample project来说明问题并将问题作为基础。
该应用使用UITableView
可重复使用的单元格;每个单元格上都有一个UIImageView
,其图像由某个URL下载
还定义了一个用于在后台队列上下载图像的信号:
- (RACSignal *)signalForLoadingImage:(NSString *)imageURLString
{
RACScheduler *scheduler = [RACScheduler
schedulerWithPriority:RACSchedulerPriorityBackground];
return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURLString]];
UIImage *image = [UIImage imageWithData:data];
[subscriber sendNext:image];
[subscriber sendCompleted];
return nil;
}] subscribeOn:scheduler];
}
在cellForRowAtIndexPath:
中,我使用image
宏将加载信号绑定到图片视图的RAC
属性:
RAC(cell.kittenImageView, image) =
[[[self signalForLoadingImage:self.imageURLs[indexPath.row]]
takeUntil:cell.rac_prepareForReuseSignal] // Crashes on multiple binding assertion!
deliverOn:[RACScheduler mainThreadScheduler]]; // Swap these two lines to 'fix'
现在,当我运行应用程序并开始向上和向下滚动表格视图时,应用程序崩溃并显示断言消息:
Signal <RACDynamicSignal: 0x7f9110485470> name: is already bound to key path "image" on object <UIImageView: <...>>, adding signal <RACDynamicSignal: 0x7f9110454510> name: is undefined behavior
但是,如果我首先将图像加载信号包装到deliverOn:
,然后再装入takeUntil:
,则单元格重用将正常工作:
RAC(cell.kittenImageView, image) =
[[[self signalForLoadingImage:self.imageURLs[indexPath.row]]
deliverOn:[RACScheduler mainThreadScheduler]]
takeUntil:cell.rac_prepareForReuseSignal]; // No issue
所以我的问题是:
image
属性,但我完全不确定它是如何发生的。感谢您阅读: - )
答案 0 :(得分:2)
我还没有证实这一点,但这里有一个可能的解释:
prepareForReuse
被调用。rac_prepareForReuseSignal
发送一个值。deliverTo:
,该值被分派到主队列,引入了一个runloop延迟。值得注意的是,这可以防止图像属性的同步/立即解除绑定。 cellForRowAtIndexPath:
… next runloop …
所以基本上信号应该在4到6之间解除绑定,但是-deliverTo:
重新排序取消绑定以便稍后出现。