UICollectionViewCell的背景线程SnapShot = WebCore崩溃

时间:2013-09-11 17:36:18

标签: ios objective-c uiwebview nsoperationqueue uicollectionviewcell

我试图解决的原始问题是如何在不干扰UI的情况下拍摄UICollectionViewCell的屏幕截图。我找到了一个解决方案,用于在后台线程上获取给定单元的快照,唯一的问题是如果在取消分配单元之前没有执行快照请求,它会在队列中挂起并最终导致崩溃。

[编辑] 我刚刚发现问题与单元格包含UIWebView的事实有关。当我运行以下代码时,我不断从WebCore收到EXC_BAD_ACCESS错误。 当我尝试在没有UIWebView的情况下拍摄每个单元格的背景快照时,它可以正常工作。

任何人都可以确定UIWebView / WebCore会导致此问题和/或我如何解决它?

以下是代码:

在我的UICollectionViewCell子类中,我创建了一个NSOperationQueue的单例实例:

+ (NSOperationQueue*)sharedSnapshotOperation
  {
    static dispatch_once_t pred;
    static NSOperationQueue *shared = nil;
    dispatch_once(&pred, ^{
        shared = [[NSOperationQueue alloc] init];
        shared.name =  @"Snapshot Queue";
        shared.maxConcurrentOperationCount = 1;
    });
    return shared;
  }

在同一个子类中,我为拍摄快照定义了以下方法:

- (void) snapshotAsync:(ImageOutBlock)block
  {
    CGFloat scaleFactor = [[UIScreen mainScreen] scale];
    CGRect frame = self.frame;
    __weak CALayer *layer = self.layer;

    NSBlockOperation *newBlockOperation = [[NSBlockOperation alloc]init];
    [newBlockOperation addExecutionBlock:^{

        //TAKE SNAPSHOT OF CELL 
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef context = CGBitmapContextCreate(NULL, frame.size.width * scaleFactor, frame.size.height * scaleFactor, 8, frame.size.width * scaleFactor * 4, colorSpace, kCGImageAlphaPremultipliedFirst);
        UIGraphicsBeginImageContextWithOptions(frame.size, YES /*opaque*/, scaleFactor);
        [layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        CGContextRelease(context);
        CGColorSpaceRelease(colorSpace);

        //GET MAIN QUEUE FOR DOING ULTIMATE TASK
        [[NSOperationQueue mainQueue] addOperationWithBlock:^ {
         block(image);
      }];
  }];

    self.blockOperation = newBlockOperation;

    //ADD OPERATION TO QUEUE
    [[InboxCell sharedSnapshotOperation] addOperation:self.blockOperation];
}    

同样,在同一个子类中,我声明了传递给我的异步快照方法的块:

typedef void(^ImageOutBlock)(UIImage* image);

同样,在同一个子类中,我调用上面的异步快照方法,如下所示:

__weak typeof(self) weakSelf = self;
    [weakSelf snapshotAsync:^(UIImage* image) {

      //PUT THE IMAGE IN THE CACHE (ultimate task)
      [weakSelf.delegate setCellScreenShot:image forKey:[weakSelf makeIndexingKeyForScreenShot]];
    }];

最后,如果要取消分配单元格(从UICollectionView委托调用),我尝试取消操作请求:

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell: (UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
       InboxCell *inboxCell = (InboxCell *)cell;
       [inboxCell.blockOperation cancel];
}

1 个答案:

答案 0 :(得分:0)

您是否尝试创建自己的自定义NSOperation?

这个想法是在你的单元格中为NSOperation保留一个强大的指针,它将截取它的截图。当您的单元格将被重用(方法prepareForReuse)或取消分配时,验证NSOperation(isFinished属性)的状态,以及它是否只是取消它。

我建议在UICollectionView委托中创建自己的队列,并处理其他线程中的操作。

查看NSOperation API文档: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html