私が解決しようとしていた最初の問題は、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];
}