在ARC上使用__bridge for CoreGraphics渐变时,应用程序崩溃

时间:2012-04-01 10:01:57

标签: core-graphics automatic-ref-counting gradients

我正在为iOS 5创建一个应用程序,我正在绘制一些渐变。我在ARC之前总是使用以下渐变代码,但是现在它不再适用于我的设备(但是,它可以在模拟器上工作),当我多次使用它时(所以我认为这是一个内存管理问题)。无论如何,这是代码:

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = { 0.0, 1.0 };

NSArray *colors = [NSArray arrayWithObjects:(__bridge id)startColor, (__bridge id)endColor, nil];

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

最初,没有__bridge语句,我按照Xcode的建议添加了它们。究竟是什么导致了这个问题?

2 个答案:

答案 0 :(得分:4)

我遇到了同样的问题。我已经使用CGGradientCreateWithColorComponents来解决我的问题。您必须将CGColorRef的NSArray转换为CGFloat s的数组。

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[2] = { 0.0, 1.0 };

CGFloat components[8] = { 0.909, 0.909, 0.909, 1.0,  // Start color
                          0.698f, 0.698f, 0.698f, 1.0 }; // End color

CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components,
                                     locations, 2);

答案 1 :(得分:3)

您的问题可能与startColor等变量的生命周期有关。我猜这些可能是通过UIColor的-CGColor方法创建的CGColorRefs,位于您列出的代码之上的某个位置。

正如我在this answer中描述的那样,除非你明确地保留了那些CGColorRefs,否则它们可能会在生成它们的UIColor被释放后消失。鉴于您从它们中提取CGColorRef后再也不会再使用UIColors,ARC可能会决定在您有机会使用CGColorRefs之前解除分配这些UIColors。我已经看到模拟器和实际设备之间的对象生命周期不同,所以这可以解释一个而不是另一个的崩溃。

我对此的解决方案是使用立即转换为id,如下所示:

NSArray *colors = [NSArray arrayWithObjects:(id)[color1 CGColor],
                                            (id)[color2 CGColor], nil];

编译器在转移CGColorRefs的所有权方面做了正确的事。

还有可能提前释放您的NSArray,在这种情况下,以下代码可能会确保它挂起的时间足够长:

NSArray *colors = [NSArray arrayWithObjects:(__bridge id)startColor, (__bridge id)endColor, nil];

CFArrayRef colorArray = (__bridge_retained CFArrayRef)colors;
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colorArray, locations);
CFRelease(colorArray);

这将NSArray与Core Foundation连接起来,留下一个保留计数至少为1的CFArrayRef。然后可以在渐变创建中使用它,渐变将有希望保留对它的引用,并手动释放它完成后。

但是,Bringo建议完全在Core Graphics的C API中工作,这可能是最简单的方法。我只是想我会解释你的问题的潜在根源,以防你将来遇到类似事情。