我只是为shadowPath属性配置CABasicAnimation
,这让我很好奇:
shadowAnimation.toValue = (id)newShadowPath.CGPath;
[注意:shadowAnimation是CABasicAnimation
个对象,newShadowPath
是UIBezierPath
个对象
这样可以在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
投射在那里也是正确的吗?或者我错过了这里有什么区别?
答案 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
,但是。