2011-11-16 64 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是一种特殊情况,这在这里引起了一些混淆。 –

相关问题