先从这段代码说起
UIImage *image = [UIImage imageNamed:@"xxx.png"] ;
_layer.contents = (__bridge id)image.CGImage ;
我曾经考虑要不要保持image
的强引用以防其被释放,因为我的理解是:image
被释放时,image.CGImage
就会被释放了,然而事实是image.CGImage
是不会被释放的,因为_layer.contents
保持了CGImage
的强引用,在CALayer
里contents
属性被定义成@property(strong) id contents;
,不过我还是怀疑这个strong
会起作用么?理由是,image.CGImage
是CGImageRef
类型的,而CGImageRef
是一个指针:typedef struct CGImage *CGImageRef;
,我查了一下文档,发现CGImageRef
不是Toll Free Bridging。_layer.contents = (__bridge id)image.CGImage ;
,在这段代码执行时会给image.CGImage
发送retain
消息,问题是image.CGImage
会被retain
么?
先说结论吧,答案是会被retain
,Core Foundation也是采用引用计数的机制,并且CGImageRef
跟Objective-C中的NSObject *
是类似的,既是CGImage
与NSObject
类似。
当我把_layer.contents
用NSLog打印出来之后,事情变得明确一些了,日志是这样:
NSLog(@"_layer.contents %@", [(__bridge id)image.CGImage class]);
结果是:
_layer.contents __NSCFType
日志说明,CGImage
是有isa指针的,并且指向了一个名为__NSCFType
的对象,通过调用这个函数class_getSuperclass(class)
,我看到__NSCFType
的父类是NSObject
,所以CGImage
可以被看做是NSObject
对象,或者说所有的Core Foundation中的类型都可以看做NSObject
对象。这里我推荐看一下MikeAsh的文章,看过之后你也应该明白了。
总结一下,我产生这个疑问的原因是没搞明白Core Foundation对象的结构,虽然不是所有的Core Foundation的类型都是Toll Free Bridging的,但是他们都有着与NSObject类似的内存结构,都可以对其retain或者release。正因为这样,我们才可以对其应用__bridge
或者__bridge_transfer
,你可以尝试随便对一个int *类型的值应用__bridge id转换,编译器是不允的。
int *a ;
_layer.contents = (__bridge id)a ;
而下面的代码就可以编译通过:
struct {
void *isa ;
} SimulateNSObject ;
- (void)fun
{
struct SimulateNSObject *a ;
_layer.contents = (__bridge id)a ; // 允许
}