2011-11-16 86 views
7

我有一個編譯時沒有問題的代碼。它在iPhone模擬器上運行良好,但在我的設備上,我得到了一個EXC_BAD_ACCESS。CG Gradient在模擬器上運行,但不在iPhone上

這發生在繪製漸變的輔助函數中。我跟着this tutorial來做到這一點。我的代碼如下:。

- (void) drawRect:(CGRect)rect 
{ 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGColorRef whiteColor = [UIColor whiteColor].CGColor; 
    CGColorRef lightGrayColor = [UIColor colorWithRed:230.0/255.0 
               green:230.0/255.0 
               blue:230.0/255.0 
               alpha:1.0].CGColor; 
    CGColorRef separatorColor = [UIColor colorWithRed:208.0/255.0 
               green:208.0/255.0 
               blue:208.0/255.0 
               alpha:1.0].CGColor; 
    CGRect paperRect = self.bounds; 
    CGRect nameRect = self.nameLabel.frame; 
    CGPoint sepStartPoint = CGPointMake(nameRect.origin.x, 
             nameRect.origin.x + nameRect.size.height + 2); 
    CGPoint sepEndPoint = CGPointMake(nameRect.origin.x + nameRect.size.width, 
             nameRect.origin.x + nameRect.size.height + 2); 

    drawLinearGradient(context, paperRect, lightGrayColor, whiteColor); 
    draw1PxStroke(context, sepStartPoint, sepEndPoint, separatorColor); 

} 


// Callee, where the problem is 
void drawLinearGradient(CGContextRef context, 
         CGRect rect, 
         CGColorRef startColor, 
         CGColorRef endColor) 
{ 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGFloat locations[] = { 0.0, 1.0 }; 

    NSArray *colors = [NSArray arrayWithObjects: 
         (__bridge id)startColor, 
         (__bridge id)endColor, 
         nil]; // Here is the line 

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, 
                 (__bridge CFArrayRef) colors, locations); 

    CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); 
    CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); 

    CGContextSaveGState(context); 
    CGContextAddRect(context, rect); 
    CGContextClip(context); 
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 
    CGContextRestoreGState(context); 

    CGGradientRelease(gradient); 
    CGColorSpaceRelease(colorSpace); 
} 

Xcode中的亮點第12行(具有nil];爲錯誤行

彼得Hosey,這裏的調試器輸出:

(gdb) po startColor 
<CGColor 0x1deca0> [<CGColorSpace 0x1d3280> (kCGColorSpaceDeviceGray)] (1 1) 
Current language: auto; currently objective-c 
(gdb) po endColor 
<CGColorSpace 0x1bf120> (kCGColorSpaceDeviceRGB) 
(gbd) 

我模擬器(和iPhone)在iOS 5上運行。

什麼可能導致此崩潰?

+0

這可能意味着startColor或endColor中的一個是懸掛指針;你可以顯示調用drawLinearGradient的代碼嗎? – Tommy

+0

我更新了調用代碼的要點 – ksol

+0

如果您在調試器控制檯中鍵入'po startColor'和'po endColor',您會得到什麼? –

回答

14

解決此問題的一種方法是將UIColors傳遞到您的函數中,而不是CGColorRefs,並對colors數組的每個元素使用(id)[color1 CGColor]強制轉換。這似乎是人們現在正在解決這個問題的最普遍的方式。

我指出一個使用這this answer,並且有在this Apple developer forum thread延長這個討論。如果您在聲明NSArray時使用UIColor的-CGColor方法,並將其轉換爲id,則會爲您自動橋接所有內容。如在上述聯論壇話題gparker狀態:

由文檔中描述的自動情況下,僅適用於 調用返回一個CF類型,然後 結果立即轉換成一Objective-一個Objective-C方法C對象類型。如果 對方法結果進行了其他操作,例如將其分配給CF類型的 變量,則它不再是自動的。

由於hatfinch指出,這可能意味着你的CGColorRefs放置在臨時變量不會流連您引用您的UIColors最後一次後,除非你明確地留住他們。與論壇主題中的其他人一樣,我錯誤地認爲這是橋接實現中的一個錯誤,但我可以看到我正在讀這個錯誤。

+2

雖然這實際上是一個ARC錯誤? [ARC規範](http://clang.llvm.org/docs/AutomaticReferenceCounting.html)說CF對象引用不被認爲是「可保留的對象指針」,這意味着ARC並不意味着保留CGColors。在CGColors被提取出來之後,UIColors不會被引用,所以沒有可靠的理由來期望它們的壽命超過它。如果UIColors擁有CGColors,他們在獲得釋放時將帶上CGColors。 –

+1

您的解決方法可行,但不是因爲ARC有錯誤;它的行爲如預期(參見Peter的評論和我的回答)。 – hatfinch

+0

@PeterHosey - 啊,不是一個錯誤,因爲我錯過了這個鏈接論壇主題的頂部附近:「文檔描述的自動情況只適用於調用返回CF類型的Objective-C方法,然後立即投射將結果傳遞給Objective-C對象類型,如果對方法結果做了其他任何事情,例如將其分配給CF類型的變量,則不再是自動的。它看起來像一個錯誤,因爲在NSArray工作中直接使用,但臨時CGColorRef分配不是。 '-CGColor'方法似乎是一個特例。 –

12

您不保留whiteColor和lightGrayColor活着。您從UIColors獲得的CGColorRefs不屬於永不保留的CGColorRefs。您的代碼應閱讀:

CGColorRef whiteColor = CFRetain([UIColor whiteColor].CGColor); 
CGColorRef lightGrayColor = CFRetain([UIColor colorWithRed:230.0/255.0 green:230.0/255.0 blue:230.0/255.0 alpha:1.0].CGColor); 
CGColorRef separatorColor = CFRetain([UIColor colorWithRed:208.0/255.0 green:208.0/255.0 blue:208.0/255.0 alpha:1.0].CGColor); 

// ... 

drawLinearGradient(context, paperRect, lightGrayColor, whiteColor); 
draw1PxStroke(context, sepStartPoint, sepEndPoint, separatorColor); 

CFRelease(whiteColor); 
CFRelease(lightGrayColor); 
CFRelease(separatorColor); 

你可以上訪蘋果宣佈 - [的UIColor CGColor]爲objc_returns_inner_pointer,這將使你的代碼更簡單,但屬性確實保留了非可保留指針。

+0

這比我(和其他人)錯誤地假設這是一個ARC錯誤更有意義。這聽起來像從'-CGColor'方法退出時直接轉換爲NSObject是一種特殊情況,這在這裏引起了一些混淆。 –

相關問題