尝试使用CGPathRef时,需要桥接强制转换,警告不一致

时间:2013-03-07 10:34:08

标签: objective-c automatic-ref-counting

我只是为shadowPath属性配置CABasicAnimation,这让我很好奇:

shadowAnimation.toValue = (id)newShadowPath.CGPath;

[注意:shadowAnimation是CABasicAnimation个对象,newShadowPathUIBezierPath个对象

这样可以在Xcode中看到没有错误/警告。但是,如果我这样写:

CGPathRef test = newShadowPath.CGPath;
shadowAnimation.toValue = (id)test;

这将无法编译,抛出此警告消息:

Cast of C pointer type 'CGPathRef' (aka 'const struct CGPath *') to Objective-C pointer type 'id' requires a bridged cast

所以它需要我输入:

shadowAnimation.toValue = (__bridge id)test;

现在为什么会这样?当我只使用(id)newShadowPath.CGPath 时,为什么我在初始示例中没有得到相同的错误; ?不管Xcode没有检测到任何问题,将__bridge投射在那里也是正确的吗?或者我错过了这里有什么区别?

2 个答案:

答案 0 :(得分:2)

这是由ARC造成的,以及分配发生时的魔力。

当您创建临时变量CGPathRef test并为其分配时,ARC会发现您正在使用不遵循标准内存范例的CoreBlank实例,并且不保留它或执行任何花哨的操作。< / p>

稍后,当您尝试将此非托管实例分配给保留的id类型的属性时,LLVM会立刻感到害怕,因为它认为它不必管理该实例的内存,但现在它应该开始(这是__bridge关键字的意图)。

在第一个代码片段中,它起作用的原因是因为ARC总是知道它应该将该实例视为ARC管理的,并且从不存在对它进行ARC管理的引用。

答案 1 :(得分:2)

区别的原因在于clang 3.1中引入的新(和有点复杂)转换规则。

首先,让它煮沸:

@@interface Foo : NSObject
+ (CGPathRef)bar;
@end

CGPathRef foo();

void test()
{
    // works without bridged cast:
    id a = (id)[Foo bar];

    // needs bridged cast
    id b = (__bridge id)foo();
}

因此,在投射消息的结果时,我们可以在普通函数调用需要时省略强制转换。这看起来很奇怪。

区别的原因在于ARC如何解释函数和方法名称,并导出有关所谓C retainable pointer types(Core Foundation对象)的保留计数的假设。

在ARC指南的section 3.3.2中(&#34;转换为具有已知语义的表达式的可保留对象指针类型&#34;),您将找到出现差异的原因:

  

表达式已知未保留,如果它是C的右值   可保留的指针类型,它是一个消息发送[...]

  

如果强制转换操作数已知未记录 [...]   转化被视为__bridge演员

同一部分描述了为什么这不适用于C函数以及如何对它们进行修饰以使clang能够做出类似的假设。所以我们可以修改上面的例子来摆脱C函数调用的桥接:

CGPathRef foo() __attribute__((cf_returns_not_retained));

回答你的最后一个问题:在两个地方使用桥梁是安全的。它甚至可以确保ARC选择正确的__bridge强制转换(它可以根据方法的名称选择__bridge_transfer强制转换。在这种情况下,它会使用__bridge,但是。