上一篇文章介绍了__unsafe_unretained
这里我们要借助__unsafe_unretained来理解__autoreleasing,童鞋们肯定会说__autoreleasing,这么简单,就是将指向的对象延迟销毁,这里我要将我研究__autoreleasing的过程中遇到的坑一一分析出来,如果你也遇到过,那我们可以一起讨论一下,或者你觉得我哪里分析得不对,请提出来,因为我也在学习中,如果你还没有遇到过我提出来的这些问题,你也可以看看。
这里插入一点小知识:
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
// __strong,__weak,__autoreleasing可以保证附有这些修饰符的自动变量初始化为nil
// 上面源码和下面效果等同
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
//在文件中引入以下声明即可使用这两个函数
extern void _objc_autoreleasePoolPrint();//打印注册到自动释放池中的对象
extern uintptr_t _objc_rootRetainCount(id obj);//获取对象的引用计数
在编译器选项“-S”的同时运行clang,可以取得程序汇编输出,如:
clang -S 文件名
/****************以下如果未特别说明,都是在ARC环境下****************/
/********************分割线************************/
前言:
这里先说几个坑
第一个坑,首先举两个例子:
//例一
id __unsafe_unretained obj1 = nil;
{
id obj0 = [NSMutableArray array];
[obj0 addObject:@"obj"];
obj1 = obj0;
NSLog(@"obj0 = %@", obj0);
}
NSLog(@"obj1 = %@", obj1);
//例二:
id __unsafe_unretained obj1 = nil;
{
id obj0 = [[NSMutableArray alloc]init];
[obj0 addObject:@"obj"];
obj1 = obj0;
NSLog(@"obj0 = %@", obj0);
}
NSLog(@"obj1 = %@", obj1);
看到这两个例子,编译执行,都会在最后一条语句崩溃掉,你肯定会问我,它们有啥区别啊,仅仅是obj0对象的创建方式不一样,是的,我待会就要分析它们崩溃的原因,分析中你就会发现,这两种创建方式在ARC下其实是有区别的,虽然都不用我们自己来管理内存的释放,但是,理解一下底层的ARC机制也是好的。
分析:
这两个例子中,obj0在中括号也就是作用域内,是强引用可变数组对象的,作用域外obj0强引用失效,并且没有其他指针强引用这个对象,所以自动释放持有的对象,obj1就相当于野指针,访问野指针就会崩溃,这些上一节已经分析过了,我们继续看下一个例子:
//例三:
id __unsafe_unretained obj1 = nil;
{
id obj0 = [NSMutableArray arrayWithObjects:@"obj",nil];
obj1 = obj0;
NSLog(@"obj0 = %@", obj0);
}
NSLog(@"obj1 = %@", obj1);
编译执行,正常打印信息:
2016-11-13 16:14:58.373 DebugDemo[3605:119189] obj0 = (
obj
)
2016-11-13 16:14:58.374 DebugDemo[3605:119189] obj1 = (
obj
)
怎么回事,为什么没有崩溃,说好的野指针呢?这会有木有觉得自己掉坑里了,反正我当时是一脸懵逼...
问题我们先留在这里,我们先来看看编译器ARC的实现,再来详细分析为什么
再来说说第二个坑
+ (id)Object
{
return [NSMutableArray array];
}
+ (id)allocObject
{
return [NSMutableArray array];
}
执行以下代码:
//例四
id __unsafe_unretained obj1 = nil;
{
id obj0 = [[self class] Object];
[obj0 addObject:@"obj"];
obj1 = obj0;
NSLog(@"obj0 = %@", obj0);
}
NSLog(@"obj1 = %@", obj1);
执行结果,正常打印,不会崩溃
那么我们将类方法修改成如下:
+ (id)Object
{
NSMutableArray *marr = [NSMutableArray array];
return marr;
}
再执行,崩溃,这里我们标记为例五
我们再调用以alloc开头的类方法:
//例六
id __unsafe_unretained obj1 = nil;
{
id obj0 = [[self class] allocObject];
[obj0 addObject:@"obj"];
obj1 = obj0;
NSLog(@"obj0 = %@", obj0);
}
NSLog(@"obj1 = %@", obj1);
还是崩溃
扩展:如果将两个类方法的实现换成如下,则会怎么样;
return [[NSMutableArray alloc]init];
答案是都会崩溃
/********************分割线************************/
我们先来看看alloc的情况
{
id __strong obj = [[NSObject alloc] init];
}
我们来看看它的模拟源代码: