RAC和单元重用:将deliveryOn:放在正确的位置?

问题描述 投票:3回答:1

[我正在使用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

所以我的问题是:

  1. 如何解释为什么后者有效而前者无效?显然,有些竞争情况导致新信号在现有信号完成之前绑定到image属性,但是我完全不确定它是如何发生的。
  2. 为了避免在RAC驱动的代码中出现这种微妙之处,我应该记住什么?我是否在上面的代码中缺少一些基本原理,还是有任何适用的经验法则(当然,假设RAC本身没有错误)?
  3. 感谢您阅读这里:-)

我正在使用RAC,尤其是Colin Eberhardt的Twitter搜索示例,遇到了我无法向自己解释的崩溃。这是我创建的示例项目...

ios objective-c reactive-cocoa
1个回答
2
投票

我尚未确认,但这是可能的解释:

© www.soinside.com 2019 - 2024. All rights reserved.