2011-09-27 104 views
1

我有點奇怪的問題。我使用imageNamed從它創建一個UIImage提取顏色數據,然後將其設置爲另一個類。EXC_BAD_ACCESS在保留的UIImage上調用drawRect

然後從那個類當我做一個drawRect時,我得到一個EXC_BAD_ACCESS時做drawRect。

這裏就是我加載圖像:

UIImage* pImageHM = [UIImage imageNamed:@"Heatmap2.png"]; 
CGImageRef irHM  = [pImageHM CGImage]; 
CFDataRef drHM  = CGDataProviderCopyData(CGImageGetDataProvider(irHM)); 
R8G8B8A8* pDataHM  = (R8G8B8A8*)CFDataGetBytePtr(drHM); 

unsigned int colour  = 0; 
unsigned int colourMax = 256; 
while(colour < colourMax) 
{ 
    // Extract image data. 
    colour++; 
} 
[mpView SetScale: pImageHM]; 

CFRelease(drHM); 
CGImageRelease(irHM); 

的SetScale函數的定義如下:

- (void) SetScale: (UIImage*)pImage 
{ 
    [mpScale release]; 

    mpScale = pImage; 

    [mpScale retain]; 

    [self setNeedsDisplay]; 
} 

最後我使其如下:

CGContextRotateCTM(ctx, -M_PI_2); 
    CGContextTranslateCTM(ctx, -(rect.size.height - 48), 0); 

    [mpScale drawInRect: CGRectMake(0,     rect.size.width - 16, 
            rect.size.height - 48, 16)]; 

    CGContextTranslateCTM(ctx, (rect.size.height - 48), 0); 
    CGContextRotateCTM(ctx, M_PI_2); 

爲什麼mpScale會提出一個EXC_BAD_ACCESS?鑑於UIImage已被保留的事實,它後來被稱爲SetScale自動釋放的事實應該既不在這裏也不在那裏。

我應該補充說,如果我不打電話SetScale(如mpscale保持爲零),那麼我沒有崩潰,顯然,我沒有看到任何規模應該是。

在此先感謝!

回答

4

CGImageRef irHM = [pImageHM CGImage];

你並不擁有這個CGImage,但你釋放它。

CGImageRelease(irHM);

+0

Ahh my bad。我知道這會是一件愚蠢的事情。 – Goz

1

在活動pImage == mpScale,當你調用SetScale你將釋放圖像,設置它,然後保留什麼。 mpScale在那一點將指向一個無效的對象。

2

您在這裏有許多問題:

  • 你SetScale方法不遵循Cocoa naming conventions (see here)。說它setScale以一個小寫的「設置」前綴,它被認爲是二傳(因此允許KVC工作,點符號自動工作,等等)

  • 您必須檢查mpImage和pImage是在實現setScale setter時不是同一個對象。如果你不這樣做,你最終會得到一個EXC_BAD_ACCESS(可能是你擁有的那個),因爲在影響+保留它之前你會釋放這個對象,所以在你有機會再次保留它之前它會達到一個爲零的retainCount。

你的二傳手應該是:

-(void)setScale:(UIImage*)pImage 
{ 
    // only do this if the variables don't point to the same object in memory to avoid crash 
    if (mpImage != pImage) { 
     [mpImage release]; // release old value 
     mpImage = [pImage retain]; // retain new one 
    } 
} 

而且(這是你的EXC_BAD_ACCESS的真正原因),你是釋放irHM(在你的代碼的最後一行CGImageRelease),但你不應該(你沒有保留它或之前取得它的所有權)

CGImageRef irHM  = [pImageHM CGImage]; 
CFDataRef drHM  = CGDataProviderCopyData(CGImageGetDataProvider(irHM)); 
... 
[mpView SetScale: pImageHM]; 

CFRelease(drHM); // <-- that's ok because you did use a "...Copy..." method 
// CGImageRelease(irHM); // <-- you DON'T need nor should do that !!