我正在尝试在UIImage
中绘制几个UIView
,我正在用drawRect:
手动完成。鉴于图像是从Web动态下载的,我创建了一个NSOperation
并从第二个线程执行图像加载代码,以保持UI响应。因此,一旦下载了图像,它们就会出现在屏幕上。
但是......对于每张图片,我都会收到以下错误:
<Error>: CGContextSaveGState: invalid context 0x0
<Error>: CGContextSetBlendMode: invalid context 0x0
<Error>: CGContextSetAlpha: invalid context 0x0
<Error>: CGContextTranslateCTM: invalid context 0x0
<Error>: CGContextScaleCTM: invalid context 0x0
<Error>: CGContextDrawImage: invalid context 0x0
<Error>: CGContextRestoreGState: invalid context 0x0
对于我所看到的,这意味着我尝试[image drawInRect...]
的上下文是nil
,因为我不再在drawRect:
。
尝试做
UIGraphicsPushContext(UIGraphicsGetCurrentContext());
在绘制图像之前但没有任何改变。我怎么能克服这件事?多线程是响应的必要条件,上下文在路上迷失。
更新:这是我的代码:
- (void)drawContentView:(CGRect)r
{
CGContextRef context = UIGraphicsGetCurrentContext();
....
CGContextFillRect(context, r);
UIApplication* app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = YES;
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:@selector(loadPreview)
object:nil];
[queue addOperation:operation];
[operation release];
}
然后
-(void)loadPreview
{
self.preview = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString:self.picStringPreview]]];
[self.preview drawInRect:CGRectMake(256, 18, 80, 65)];
}
我尝试在UIGraphicsPushContext...
中添加loadPreview
,即使在那里[self performSelectorOnMainThread...]
也没有。这是一个基于Atebit模型的自定义单元格,因此我的单元格的超类使:
- (void)drawRect:(CGRect)r
{
[(ABTableViewCell *)[self superview] drawContentView:r];
}
并且drawContentView:
中的代码在超类的drawRect:
中被绘制。任何提示?
答案 0 :(得分:3)
当你开始绘制图像时,你对上下文的了解非常正确。 UIKit在调用drawRect:
之前为您的视图设置绘图上下文,之后它被销毁。作为一般规则,在您从框架类继承的draw...
方法中,只有并且始终是为您设置的上下文。
那你能做什么?它实际上应该很容易。事实上,Anomie的回答已经告诉过你了。您需要做的就是在drawContentView:
中调用图像上的draw方法,在那里您知道自己有上下文。在loadPreview
方法中,您拨打setNeedsDisplay
*,在drawContentView:
中检查preview
是nil
,如果没有,则绘制。{只是为了扩展Anomie的答案,这里的代码应该是这样的:
-(void)loadPreview
{
self.preview = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString:self.picStringPreview]]];
[self setNeedsDisplay];
}
- (void)drawContentView:(CGRect)r
{
CGContextRef context = UIGraphicsGetCurrentContext();
....
CGContextFillRect(context, r);
UIImage * prvw = self.preview; // Avoid making two method calls
if( prvw ){
[prvw drawInRect:CGRectMake(256, 18, 80, 65)];
}
// etc.
您最好还是可以创建和调度绘图方法的NSOperation
out 。建议所有绘图方法仅 他们需要做什么,并尽快终止。
*我认为Anomie可能需要通过performSelector:...onMainThread:
来调用,因为setNeedsDisplay
没有直接调用drawRect:
,只是设置了一个标志。
答案 1 :(得分:2)
最简单的方法是不要弄乱drawRect:
,而是将图像放在UIImageViews中。 Apple声称即使是空的drawRect:
也会改变某些东西,或者使其变得更慢。
但如果必须,你必须将图像保存到班级中的ivars(不要忘记保留它们),调用setNeedsDisplay
或setNeedsDisplayInRect:
(在主线程上,所以您需要使用performSelector:withObject:onMainThread:
(如果您还没有)通知系统它需要再次呼叫您的drawRect:
,然后再次调用drawRect:
时使用保存的图像画画。