引用计数器
1.引用计数器,是伴随对象的产生而产生的。
当我们执行下面语句的时候,它就产生了一个对象,并且默认该对象的引用计数器为1:
id obj = [[NSObject alloc] init];
NSLog(@"obj retainCount=%lx", [obj retainCount]);
输出结果:
2014-07-29 18:32:59.346 Test_ARC_bridge[1127:303] obj retainCount=1
2.当我们在上面的代码加上另外一些代码时,如下(在ARC无效的情况下运行): id obj = [[NSObject alloc] init];
void *p =obj;
[(id)p retain];
NSLog(@"p retainCount=%lx", [(id)p retainCount]);
NSLog(@"obj retainCount=%lx", [obj retainCount]);
输出结果:
2014-07-29 18:26:49.324 Test_ARC_bridge[1100:303] p retainCount=2
2014-07-29 18:26:49.327 Test_ARC_bridge[1100:303] obj retainCount=2
分析上面代码:
void *p =obj;
[(id)p retain];//retainCount+1
__bridge、__birdge_retained与__bridge_transfer
1.当我们在ARC有效的情况下运行下面代码:
id obj = [[NSObject alloc] init];
void *p =obj;
你会发现在,ARC有效的情况下,编译器不允许你隐式的将Object-C 指针转换成C指针,即有如下错误提示:
2.__bridge
查阅相关文档,我们可以用
__bridge
关键字来解决这一问题,修改代码如下:
id obj = [[NSObject alloc] init];
void *p =(__bridge void *)obj;
NSLog(@"obj retainCount=%x", _objc_rootRetainCount(obj));
编译通过,输出结果:
2014-07-29 19:07:16.807 Test_ARC_bridge[1296:303] obj retainCount=1 //即P指针指向的该实体仍然是有效的
注意:在使用ARC的时候,编译器不在允许我们明确调用retainCount函数了,使用会报错滴!(因为,
ARC模式就是不需要你关心引用计数)
3.__bridge_retained
修改代码,使用__bridge_retained关键字代替__bridge关键字:
id obj = [[NSObject alloc] init];
void *p =(__bridge_retained void *)obj;
NSLog(@"obj retainCount=%x", _objc_rootRetainCount(obj));
输出结果:
2014-07-29 19:18:04.187 Test_ARC_bridge[1315:303] obj retainCount=2
结合2和3两点,我们知道__bridge 与__bridge_retained的区别是,对象又有权的不同。即__bridge关键字,不对对象的引用计数器进行任何处理,而__bridge_retained
关键字则会让对象的引用计数器+1。同理,我们也可以推断出__bridge_transfer关键字是否同样对对象的所有权做了某些处理呢?
输出结果:
4.__bridge_transfer
修改代码,验证__bridge_transfer关键字的作用:
id obj = [[NSObject alloc] init];
void *p =(__bridge_retained void *)obj;
NSLog(@"obj retainCount=%x", _objc_rootRetainCount(obj));
id objOther= (__bridge_transfer id)p;
NSLog(@"objOther retainCount=%x", _objc_rootRetainCount(objOther));
输出结果:
2014-07-29 20:20:55.984 Test_ARC_bridge[1723:303] obj retainCount=2
2014-07-29 20:20:55.987 Test_ARC_bridge[1723:303] objOther retainCount=2
结果很让人意外啊:为什么还是2?
以上代码和结论只提供参考,个人水平有限,不一定准确。在此也是为了做个笔记,方便以后翻阅时能解决该疑惑!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
参考其他文章引用过来的结论:
对象所有权策略是基于引用计数实现的
对象所有权的策略是通过引用计数——通常叫做retain count实现的。每一个对象有一个retaincount变量。
1.创建对象后,它的retaincount是1
2. retain之后,retain count +1
3.release之后 retain count -1
4.autorelease之后,在自动释放池最后-1
5.对象的retain count减少到0的时候,对象被销毁。
【重要】
不要显式调用对象的retainCount,结果往往具有误导性,作为开发者可能不了解框架式如何对对象retain的。在调试内存管理中,你应该只关注确保你的代码遵循所有权规则。
个人初步结论:
1. __bridge_retained 告诉ARC 一旦__bridge_retained转换完成,ARC就不用在负责释放该对象了,使用者需要手动释放,即使用者拥有该对象的持有权。相当于:
id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];
//即当obj变量被释放(出了大括号作用于)时,p变量仍然持有对象的所有权
2. __bridge_transfer 告诉ARC 一旦__bridge_transfer转换完成,ARC要负责释放该对象!相当于:
// p 变量原先持有对象的所有权
id obj = (id)p;
[obj retain];
[(id)p release];
//此后,ARC负责对obj对象所有权的管理
参考文章:
http://blog.csdn.net/weiwangchao_/article/details/7744972
Core Foundation 框架 (有详细的说明)
http://book.2cto.com/201305/23871.html
_objc_rootRetainCount 函数
http://www.cocoachina.com/applenews/devnews/2013/1126/7418.html
iOS内存管理策略和实践