我试图解决的原始问题是如何在不干扰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];
}
答案 0 :(得分:0)
您是否尝试创建自己的自定义NSOperation?
这个想法是在你的单元格中为NSOperation保留一个强大的指针,它将截取它的截图。当您的单元格将被重用(方法prepareForReuse)或取消分配时,验证NSOperation(isFinished属性)的状态,以及它是否只是取消它。
我建议在UICollectionView委托中创建自己的队列,并处理其他线程中的操作。
查看NSOperation API文档: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html