clang编译oc文件:
编译单个:clang -fobjc-arc -framework Foundation main.m -o main/clang -fno-objc-arc -framework Foundation main.m -o main
编译多个:clang -fobjc-arc -framework Foundation main1.m main2.m -o main/......
NSLog的格式如下所示:http://www.jianshu.com/p/00c773e73b56
%@ 对象
%d, %i 整数
%u 无符整形
%f 浮点/双字
%x, %X 二进制整数
%o 八进制整数
%zu size_t
%p 指针
%e 浮点/双字 (科学计算)
%g 浮点/双字
%s C 字符串
%.*s Pascal字符串
%c 字符
%C unichar
%lld 64位长整数(long long)
%llu 无符64位长整数
%Lf 64位双字
objc_autoreleaseReturnValue和objc_retainAutoreleasedReturnValue
ARC对于以new,copy
,mutableCopy
和alloc
以及 以这四个单词开头的所有函数,默认认为函数返回值直接持有对象。这是ARC中必须要遵守的命名规则。
http://luoxianming.cn/2017/05/06/arc/ ----->release 和retain的优化
ARC对使用非alloc/new/copy/mutableCopy等开头生成对象的方法,都会调用上述两个方法(目的:优化内存管理机制),比如array类方法会变成下面这样,objc_autoreleaseReturnValue函数替代了autorelease方法:
+ (id) array {
NSMutableArray *array = [[NSMutableArray alloc] init];
objc_autoreleaseReturnValue(array);
}
当在外部调用array方法赋值时方法是这样,objc_retainAutoreleasedReturnValue函数替代了retain方法:
id temp = [NSMutable array];
id obj = objc_retainAutoreleasedReturnValue(temp);
实现优化的原理:
1、被调方和调用方都使用ARC
在返回值身上调用objc_autoreleaseReturnValue
方法时,runtime将这个返回值object储存在TLS中,然后直接返回这个object(不调用autorelease);同时,在外部接收这个返回值的objc_retainAutoreleasedReturnValue
里,发现TLS中正好存了这个对象,那么直接返回这个object(不调用retain)。于是乎,调用方和被调方利用TLS做中转,很有默契的免去了对返回值的内存管理。
id objc_autoreleaseReturnValue(id object) {
if ( //调用者将会执行retain ) {
set_flag(object);//存储在TLS(线程局部存储)
return object;
} else {
return [object autorelease];
}
}
id objc_retainAutoreleasedReturnValue(id object) {
if (get_flag(object)) {
clear_flag(object);
return object;
} else {
return [object retain];
}
}
2、调用方使用ARC,被调方(例如:第三方类库)使用MRC
如果一个函数返回前知道调用方是ARC还是非ARC,就有机会对于不同情况做不同的处理
使用内建函数char *__builtin_return_address(int level)
作用是得到函数的返回地址,参数表示层数;如__builtin_return_address(0)表示当前函数体返回地址,传1是调用这个函数的外层函数的返回值地址,以此类推。这意味着被调用函数可以得到此次调用结束的地址,通过在该地址上加上偏移量,被调方可以定位到主调方在返回值后面的汇编指令。于是可以借助static bool callerAcceptsFastAutorelease(const void * const ra0),入参是char *__builtin_return_address(int level)
返回值。
if(*sym != objc_retainAutoreleasedReturnValue) {
return false;
}
它检验了主调方在返回值之后是否紧接着调用了objc_retainAutoreleasedReturnValue
,如果是,就知道了外部是ARC环境,反之就走没被优化的老逻辑。
IOS Autorelease对象:@autoreleasepool 、 NSAutoreleasePool
两者都是对autoreleasepool进行操作。
在MRC时代,每个主线程会自动创建一个autoreleasePool,将对象标志为autorelease,就会将该对象放入autoreleasePool,池子释放的时候,对象也会被释放掉。
在没有手动添加AutoreleasePool的情况下,Autorelease对象是在当前的runloop
迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop。
ARC时代,NSAutoreleasePool、autorelease等都不允许在程序中出现。@autoreleasepool是对NSAutoreleasePool的优化(不用在手动对对象调用autorelease,ARC会自动添加),适用于MRC和ARC环境下。
Autorelease释放原理:http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
秉着谁创建谁释放的原则,返回值需要是一个autorelease对象才能配合调用方正确管理内存,于是乎编译器改写成了形如下面的代码:
+ (instancetype)createSark {
id tmp = [self new];
return objc_autoreleaseReturnValue(tmp); // 代替我们调用autorelease
// caller
id tmp = objc_retainAutoreleasedReturnValue([Sark createSark]) // 代替我们调用retain
Sark *sark = tmp;
objc_storeStrong(&sark, nil); // 相当于代替我们调用了release