我正在尝试在 UIImage
中绘制几个 UIView
,并且我正在使用 drawRect:
手动完成。鉴于图像是从网络动态下载的,我创建了一个 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 模型的自定义单元格,所以我的单元格的父类(super class)使:- (void)drawRect:(CGRect)r
{
[(ABTableViewCell *)[self superview] drawContentView:r];
}
drawContentView:
中的代码在父类(super class)的 drawRect:
中被绘制。任何提示? 最佳答案
当您开始绘制图像时,上下文已经消失,这是非常正确的。 UIKit 在 drawRect:
被调用之前为你的 View 设置一个绘图上下文,然后它会被销毁。作为一般规则,在从框架类继承的 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
的创建和调度移出绘图方法。建议所有绘图方法只做他们需要做的事情,并尽快终止。*我认为 Anomie 需要通过
performSelector:...onMainThread:
调用它可能是错误的,因为 setNeedsDisplay
不直接调用 drawRect:
,它只是设置了一个标志。关于objective-c - drawRect中上下文和线程之间的问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6025682/