2011-05-17 77 views
3

我試圖在UIView中繪製幾個UIImage,我正在用drawRect:手動執行。鑑於圖像是從網上動態下載的,我創建了一個NSOperation,並從第二個線程執行圖像加載代碼,以保持UI響應。所以一旦圖像被下載,它們就會出現在屏幕上。上下文和線程在drawRect之間的問題

但是...我遇到下面的錯誤,每個圖像的:

<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)]; 
} 

我嘗試添加在loadPreview一個UIGraphicsPushContext...,甚至做一個[self performSelectorOnMainThread...]那裏,並沒有什麼。這是基於Atebit的模型的自定義單元格,所以我的手機的超做:

- (void)drawRect:(CGRect)r 
{ 
    [(ABTableViewCell *)[self superview] drawContentView:r]; 
} 

drawContentView:代碼在超類的drawRect:被draw'd。任何提示?

+0

你可以發佈一個'drawRect:'方法的片段嗎?你是在創建'NSOperation' _inside_'drawRect:',然後試圖從其他線程中繪製圖像? – 2011-05-17 02:51:17

+0

我現在不在家,只要我回來,我會用片段更新我的問題。謝謝! – ferostar 2011-05-17 12:50:44

+0

只是更新後的代碼片段 – ferostar 2011-05-18 01:24:46

回答

3

在繪製圖像時,你對上下文消失的看法是非常正確的。在調用drawRect:之前,UIKit會爲您的視圖設置繪圖環境,並在之後銷燬。作爲一般規則,在您從框架類繼承的draw...方法中,只會始終爲您設置上下文。

那麼你能做什麼?它實際上應該很容易。事實上,Anomie的回答已經告訴過你。所有你需要做的就是調用你的圖像上的繪製方法回到drawContentView:,你知道你有一個上下文。在loadPreview方法中,您可以撥打setNeedsDisplay *,並在drawContentView:中檢查preview是否爲nil,如果不是,則繪圖。只是對失範的答案擴大,這裏的代碼應該是什麼樣子:

-(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的創建和調度出來的繪製方法 。建議所有繪圖方法只做他們需要做的事情並儘快終止。


*我認爲失範可能是錯誤的約需要通過performSelector:...onMainThread:調用這個,因爲setNeedsDisplay不叫drawRect:直接,它只是設置一個標誌。

2

這樣做最直接的方法是不要混淆drawRect:,而是將圖像放在UIImageView中。 Apple聲稱,即使是空的drawRect:也會改變渲染速度慢的東西。

但是,如果你要,你就必須在圖像的ivars保存在您的類(不要忘記留住他們),撥打setNeedsDisplaysetNeedsDisplayInRect:(在主線程,所以你需要使用performSelector:withObject:onMainThread:如果您還沒有)通知系統需要再次調用您的drawRect:,然後再次調用drawRect:時,使用保存的圖像進行繪製。