为什么GCD代码在drawRect中崩溃?

时间:2012-05-26 11:33:37

标签: iphone objective-c ios grand-central-dispatch

这是在drawRect:

NSString *generated = [Entry generateString];

const char *cString = (const char*)[generated UTF8String];

dispatch_queue_t queue = dispatch_queue_create(cString, NULL);*/

dispatch_async(queue, ^{

    Media *media = [self.entry.media objectAtIndex:i];

    UIImage *image = [media getThumbnail];

    dispatch_async(dispatch_get_main_queue(), ^{

        int bottom = [JHomeViewCell yOfMessageBottomWithMessageHeight:self.cellInfo.messageHeight
                                                            withMonth:self.cellInfo.hasMonth];

        CGRect frame = CGRectMake(87 + (68 * i),
                                  bottom,
                                  THUMBNAIL_SIZE.width,
                                  THUMBNAIL_SIZE.height);

        [image drawInRect:frame];
    });

});

现在,它正在objectAtIndex行崩溃。这不是一个无效的索引。代码在这里工作正常。

编辑:我收到了这个错误:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'statement is still active'

编辑2:我放入NSLogs,第一个获得media.count。它崩溃了同样的错误。

1 个答案:

答案 0 :(得分:6)

这里的问题是你在你应该去的地方以外的地方画画。当您从drawRect:返回时,您告诉操作系统您已完成。你不能在从drawRect:返回之前产生一个异步线程,并期望能够通过回到主线程来绘制,因为一旦从drawRect:返回,上下文就会被破坏。

通常的做法是在单独的线程上缓存信息,然后在需要绘制的区域上调用invalidateRect:,允许drawRect:方法除了快速绘制外什么也不做并退出。

如果您想延迟加载缩略图,我建议将缩略图的副本存储在私有位置(可能使用NSCache并使用您的图像标识符作为密钥),然后如果图像存在于缓存中{调用{1}},绘制图像,否则绘制占位符并使用GCD将图像添加到队列以创建缩略图。在该调度队列调用内部:

  • 检索缩略图
  • 将其存储在缓存中
  • 在包含图片
  • 的区域调用drawRect:

如果您发现难以计算位置,或者您很快得到缩略图,则可以延迟invalidateRect:并在绘制例程结束时调用最终的dispatch_async(但仅限于用于检索的排队缩略图)。这将导致单个全区域重绘,而不是包含单个缩略图的每个区域的多次重绘。