クリッピング、ストローク、透明度で描画するカスタム UICollectionViewCell サブクラスがあります。Simulator と iPhone 5 では問題なく動作しますが、古いデバイスでは顕著なパフォーマンスの問題があります。
そこで、時間のかかる描画をバックグラウンド スレッドに移動したいと考えています。-drawRect メソッドは常にメインスレッドで呼び出されるため、描画されたコンテキストを CGImage に保存することになりました (元の質問には CGLayer を使用したコードが含まれていましたが、Matt Long が指摘したように時代遅れです)。
このクラス内の drawRect メソッドの実装は次のとおりです。
-(void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
if (self.renderedSymbol != nil) {
CGContextDrawImage(ctx, self.bounds, self.renderedSymbol);
}
}
この renderSymbol プロパティを定義するレンダリング メソッド:
- (void) renderCurrentSymbol {
[self.queue addOperationWithBlock:^{
// creating custom context to draw there (contexts are not thread safe)
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef ctx = CGBitmapContextCreate(nil, self.bounds.size.width, self.bounds.size.height, 8, self.bounds.size.width * (CGColorSpaceGetNumberOfComponents(space) + 1), space, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(space);
// custom drawing goes here using 'ctx' context
// then saving context as CGImageRef to property that will be used in drawRect
self.renderedSymbol = CGBitmapContextCreateImage(ctx);
// asking main thread to update UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self setNeedsDisplayInRect:self.bounds];
}];
CGContextRelease(ctx);
}];
}
このセットアップはメイン スレッドで完全に機能しますが、NSOperationQueue または GCD でラップすると、さまざまな「無効なコンテキスト 0x0」エラーが発生します。アプリ自体はクラッシュしませんが、描画は行われません。カスタム作成した CGContextRef のリリースに問題があると思いますが、どうすればよいかわかりません。
これが私のプロパティ宣言です。(アトミックバージョンを使用してみましたが、役に立ちませんでした)
@property (nonatomic) CGImageRef renderedSymbol;
@property (nonatomic, strong) NSOperationQueue *queue;
@property (nonatomic, strong) NSString *symbol; // used in custom drawing
プロパティのカスタム セッター/ゲッター:
-(NSOperationQueue *)queue {
if (!_queue) {
_queue = [[NSOperationQueue alloc] init];
_queue.name = @"Background Rendering";
}
return _queue;
}
-(void)setSymbol:(NSString *)symbol {
_symbol = symbol;
self.renderedSymbol = nil;
[self setNeedsDisplayInRect:self.bounds];
}
-(CGImageRef) renderedSymbol {
if (_renderedSymbol == nil) {
[self renderCurrentSymbol];
}
return _renderedSymbol;
}
私に何ができる?