【发布时间】:2013-05-14 13:48:23
【问题描述】:
我有自定义 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 包装它时,我得到了很多不同的“invalid context 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,因为您在renderedSymbol中异步调用renderCurrentSymbol但会立即返回_renderedSymbol。 -
您是否尝试过在释放 CGLayer 之前不执行 CGContextRelease(ctx)(大概在 dealloc 中?)
-
@MikePollard 释放上下文是正确的,如果你不释放上下文就会有内存泄漏。
-
是的,我不是建议不释放它,而是在dealloc中释放它,这大概是释放CGLayer的地方,否则此刻正在泄漏。
-
invalid context 0x0 通常意味着您的
CGContext为 nil 或其大小为零。你应该为这两件事调试你的程序。
标签: ios multithreading uiview core-graphics cglayer