NSManagedObject的KVO方法调用外部二进制数据属性使表视图滚动迟缓,为什么?

时间:2012-08-08 22:23:11

标签: ios uitableview core-data nsfetchedresultscontroller

经过数周的调试,我终于在桌面视图滚动过程中找到了零星滞后的罪魁祸首。它们是-willChangeValueForKey:-didChangeValueForKey:调用外部二进制数据属性。

为方便起见,您可以将我的应用视为Twitter客户端。因此,主要实体是Tweet,其thumbnail_pic_data属性设置为allowsExternalBinaryDataStorage。名为thumbnail_picture的相应非持久性属性用作其方便的访问者。

表格视图是推文列表视图 - 时间轴,每条推文的thumbnail_picture都显示在其相应单元格的内联中。图片是懒洋洋地下载的。下载成功后,我使用自定义设置器设置thumbnail_pic_data,如下所示:

- (void)setThumbnail_pic_data:(NSData *)thumbnail_pic_data {
    [self willChangeValueForKey:@"thumbnail_pic_data"]; // culprit
    [self setPrimitiveThumbnail_pic_data:thumbnail_pic_data];
    [self didChangeValueForKey:@"thumbnail_pic_data"]; // culprit

    UIImage *picture;
    if (thumbnail_pic_data) {
        picture = [UIImage imageWithData:thumbnail_pic_data];
    }
    self.thumbnail_picture = picture;
}

使用上面的代码,我看到在每次下载图片后我的表格视图中滚动的零星滞后。在我评论willChangeValueForKey:didChangeValueForKey:来电后,滞后消失了。所以我知道他们是罪魁祸首。

但是,我使用以下代码得到的时序结果显示,他们长时间不使用CPU直接

CFAbsoluteTime t1 = CFAbsoluteTimeGetCurrent();
[self willChangeValueForKey:@"thumbnail_pic_data"];
CFAbsoluteTime t2 = CFAbsoluteTimeGetCurrent();
NSLog(@"willChangeValueForKey time: %f", t2 - t1);
[self setPrimitiveThumbnail_pic_data:thumbnail_pic_data];
CFAbsoluteTime t3 = CFAbsoluteTimeGetCurrent();
NSLog(@"setPrimitiveThumbnail_pic_data time: %f", t3 - t2);
[self didChangeValueForKey:@"thumbnail_pic_data"];
CFAbsoluteTime t4 = CFAbsoluteTimeGetCurrent();
NSLog(@"didChangeValueForKey time: %f", t4 - t3);

计时结果:

  

willChangeValueForKey时间:0.000145
  setPrimitiveThumbnail_pic_data时间:0.001512
  didChangeValueForKey时间:0.001810

     

willChangeValueForKey时间:0.000138
  setPrimitiveThumbnail_pic_data时间:0.001418
  didChangeValueForKey时间:0.002211

     

willChangeValueForKey时间:0.000302
  setPrimitiveThumbnail_pic_data时间:0.001891
  didChangeValueForKey时间:0.003349

     

willChangeValueForKey时间:0.000162
  setPrimitiveThumbnail_pic_data时间:0.001462
  didChangeValueForKey时间:0.002114

作为临时解决方法,我会留下这两个KVO电话注释掉。我不确定Core Data Programming Guide是否会发生任何不好的事情:

  

您必须确保调用相关的访问和更改通知方法(willAccessValueForKey:,didAccessValueForKey:,willChangeValueForKey:,didChangeValueForKey:,willChangeValueForKey:withSetMutation:usingObjects:和didChangeValueForKey:withSetMutation:usingObjects :)。

最重要的是,我想知道为什么这两个KVO调用会使表格视图滚动缓慢,以便我能找到更好的解决方法。

2 个答案:

答案 0 :(得分:0)

请允许我建议一种不同的方法,而不是将数据/图像保存为瞬态属性,将瞬态属性另存为图像名称。图像的NSData对象看起来没用,所以,不要浪费内存保留它,因为看起来你需要内容的唯一东西是生成图像,而是用Web上的NSData创建NSImage对象,并将其分配给NSCache值,其中包含图像名称(NSManagedObject对象的瞬态属性)作为图像对象的键。

答案 1 :(得分:-1)

最后,我发现了它。

-willChangeValueForKey:-didChangeValueForKey:将导致NSFetchedResultsControllerDelegate方法被调用,如果在我的情况下滚动期间经常调用它们,则这些方法非常耗时。省略这两个KVO调用会使我不必要的NSFetchedResultsControllerDelegate方法调用,但我不应该这样做,因为Apple doc明确地告诉我们不要这样做,而且如果我这样做,我确实会发现坏事。

基本上,此问题需要How to know which property is changed for NSFetchedResultsChangeUpdate?

的相同解决方案