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

Iva*_*vic 5 objective-c automatic-ref-counting

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

shadowAnimation.toValue = (id)newShadowPath.CGPath;
Run Code Online (Sandbox Code Playgroud)

[注意:shadowAnimation是一个CABasicAnimation对象,newShadowPath是一个UIBezierPath对象]

这是有效的,Xcode中没有错误/警告.但是,如果我这样写:

CGPathRef test = newShadowPath.CGPath;
shadowAnimation.toValue = (id)test;
Run Code Online (Sandbox Code Playgroud)

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

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

所以它需要我输入它:

shadowAnimation.toValue = (__bridge id)test;
Run Code Online (Sandbox Code Playgroud)

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

Nik*_*uhe 3

造成差异的原因在于 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();
}
Run Code Online (Sandbox Code Playgroud)

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

差异的原因在于 ARC 如何解释函数和方法名称以及如何导出有关所谓的C 可保留指针类型的保留计数的假设(Core Foundation 对象)的保留计数的假设。

在ARC 指南的第 3.3.2 节(“转换为具有已知语义的表达式的可保留对象指针类型”)中,您将找到差异的原因:

如果表达式是C 可保留指针类型的右并且它是 [...] 消息发送 [...]

如果已知强制转换操作数未保留[...],则转换将被视为 __bridge 强制转换

同一部分描述了为什么这不适用于 C 函数,以及如何修饰它们以使 clang 做出类似的假设。因此,我们也可以修改上面的示例,以消除 C 函数调用的桥接转换:

CGPathRef foo() __attribute__((cf_returns_not_retained));
Run Code Online (Sandbox Code Playgroud)

回答你的最后一个问题:在两个地方使用桥模型都是安全的。它甚至确保 ARC 选择正确的__bridge转换(它可以__bridge_transfer根据方法的名称选择转换。__bridge但在本例中它将使用 )。