У меня есть пользовательский подкласс UICollectionViewCell, где я рисую с обрезкой, поглаживанием и прозрачностью. Он отлично работает на Simulator и iPhone 5, но на более старых устройствах заметны проблемы с производительностью.Рисование в другом потоке с CGImage/CGLayer
Так что я хочу переместить отвлекающий много времени рисунок в фоновый поток. Поскольку метод -drawRect всегда вызывается в основном потоке, я закончил тем, что сохранил обратный контекст в CGImage (исходный вопрос содержал код с использованием CGLayer, но он отчасти устарел, как указал Мэтт Лонг).
Вот моя реализация метода DrawRect внутри этого класса:
-(void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
if (self.renderedSymbol != nil) {
CGContextDrawImage(ctx, self.bounds, self.renderedSymbol);
}
}
метод рендеринга, который определяет это свойство renderedSymbol:
- (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;
}
Что я могу сделать?
Ваш первый 'drawInRect' в конечном итоге приведет к созданию NULL-'CGLayer', поскольку вы вызываете' renderCurrentSymbol' асинхронным в 'renderedSymbol', но без задержки возвращаете' _renderedSymbol'. –
Вы пытались не делать CGContextRelease (ctx), пока не освободите CGLayer (предположительно, в dealloc?) –
@MikePollard Освобождение контекста является правильным, если вы не освободите контекст, у вас будет Memoryleak. –