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,mutableCopyalloc以及 以这四个单词开头的所有函数,默认认为函数返回值直接持有对象。这是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

results matching ""

    No results matching ""