【问题标题】:App crashes when using __bridge for CoreGraphics gradient on ARC在 ARC 上使用 __bridge 进行 CoreGraphics 渐变时应用程序崩溃
【发布时间】:2012-04-01 10:01:56
【问题描述】:

我正在为 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 的建议添加了它们。究竟是什么导致了这个问题?

【问题讨论】:

  • 在堆栈跟踪中什么时候崩溃?我能想到它可能会失败的几点。绘制渐变、创建渐变等时是否失败?
  • 当我与 objc 对象进行 __bridge 对话时,它会崩溃。

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


【解决方案1】:

我遇到了同样的问题。我求助于使用CGGradientCreateWithColorComponents,它为我解决了这个问题。您必须将 CGColorRefs 的 NSArray 转换为 CGFloats 的数组。

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

【讨论】:

    【解决方案2】:

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

    正如我在this answer 中所描述的,除非您明确保留这些 CGColorRef,否则它们可能会在生成它们的 UIColor 被释放后消失。鉴于从 UIColors 中提取 CGColorRefs 后您不再使用 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 中工作,这可能是最简单的方法。我只是想我会解释你的问题的潜在来源,以防你将来遇到类似的事情。

    【讨论】:

      猜你喜欢
      • 2021-08-23
      • 1970-01-01
      • 1970-01-01
      • 2012-09-20
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2015-10-29
      相关资源
      最近更新 更多