1.ARC

1.简介
该部分笔记总结自《Object-C高级编程》和《疯狂iOS讲义》

2.ARC是通过引用计数来实现一种引用计数的方式。
将对象分成4个状态,生成,持有,释放,废弃。方式如下:
生成并持有对象 alloc/new/copy/mutableCopy等方法
持有对象 retain
释放对象 release
废弃对象 dealloc
在Cocoa框架中由NSObject提供内存管理的职责。持有的对象需要释放,而非持有的对象则不需要释放。
copy返回的对象总是不可变的,mutableCopy总是可变的,copy属性也是不可变的。
3.命名规则
在自定义方法时:生成并持有对象时需以alloc/new/copy/mutableCopy。而生成但不持有对象则不能以这些方法开头
4. autorelease方法可以使对象存在,但自己不持有,会注册到autoreleasepool中去,pool结束的时候会自动释放。方法本质是调用NSAutoreleasePool方法的add Object方法,增加到自动释放池中去
5.属性说明
__strong:默认属性为强引用,会自己持有对象,超过作用域的时候会自动释放。当有__strong修饰符时,可以不用再次键入retain和release
__strong, __weak,__autoreleasing在初始化时会将对象自动赋值为nil
思考:当成员变量持有强引用时,而对象又过期,那么内部成员的强引用是否会被释放呢?
强引用容易产出循环引用,而循环引用则会容易导致内存泄漏(比如A成员变量持有对象B,B成员变量持有对象A,A成员变量持有对象自身A)。所以需特别注意
__weak:可以有效避免循环引用的出现,通常的做法是用一个临时的强引用生成对象,然后给弱引用赋值,再使用时为了安全,先判断是否为nil
__unsafe_unretained:修饰符的变量不属于编译器的内存管理对象,自己不持有对象,当对象被废弃时,并不能知晓
__autoreleasing:在ARC有效的时候,并不能使用,也不能使用NSAutoReleasePool类,使用@autoreleasepool { }进行替代
函数调用生成对象返回的时候:底层通过判断生成的对象方法是否是以alloc/new/copy/mutableCopy开始,如果不是则要注册到autoreleasepool中去,也可以通过__autoreleasing修饰符进行注册
在访问附有__weak属性对象时,是通过访问访问__autoreleasing pool来获取的对象,因为__weak为弱引用,再使用的时候该对象可能被废弃,所以为了保证对象存在,注册到__autoreleasingpool能确保该对象的存在。(Page46 不是很明白)
id/对象指针的默认所有权是strong,而id* 和双重指针默认的所有是__autoreleasing,需特别注意
id* error = id __autoreleasing* error

//错误用法举例:
NSError* error = nil;   
NSError** perror = &error;
//NSError** 默认为NSError __autorelease* perror
改成 NSError* __strong* perror = &error;  //OK
在传双重指针的参数时候,编译器会进行一次隐式的转换   
__autoreleaing修饰符职能显示指定自动变量(局部变量,函数,方法参数)

__objc_autoreleasePoolPrint():非公开函数,可以调试注册到autoreleasepool中的对象,发布的时候需要去掉,不能注释

6.使用ARC需遵循条件
内存管理由编译器完成,编译器自动添加retain/release/autorelease
1.不能使用retain/release/retainCount/autorelease
2.不能使用NSAllocateObject和NSDeallocateObject
3.必须遵守内存管理命名规则
4.不能显示调用dealloc
5.使用autoreleasepool代替NSAutoreleasePool
6.不能使用区域NSZone*
7.对象型变量不能作为C语言结构体(struct/union)的成员
8.显示转换id 和 void*

(7解释:因为C语言并没有规定成员的生存周期,OC中对象的生存周期是在编译阶段确定的,所以不能进行确定)
(8在ARC无效的时候可以直接转换,在有效时需通过桥接__bridge进行转换
id* obj = [[NSObject alloc] init];
void* obr = (__bridge void*) obj;
id* obj2 = (__bridge id) obj;

7.函数的强制命名规则
OC中编译器会对函数名进行解析,判断是否加入autoreleasepoo等,所以这部分相关函数必须命名规范:
以alloc,new,copy,mutableCopy等开始等法必须返回对象或者id
init开始的方法必须是实例方法,并且必须返回对象或者id,该方法返回的对象并不注册到autoreleasepool上
initialize:不遵循init规则,其它必须遵守

8.关于__bridge_retained,__bridge_transfer, __bridge总结
__bridge : 只是进行简单进行类型转化,并不涉及所有权交换
__bridge_retained:指针持有对象,相当于retain,对象计数器+1
__bridge_transfer:进行所有权转化,新转换的指针持有对象,原来的指针不持有对象
在ARC中用__bridge即可。
这中类型的转换多出现在Core Foundation对象和Object-C对象之间的转换

9.关于Core Foundation对象 和Object-C对象
Core Foundation对象主要使用C语言编写的CoreFoundation框架中,并使用引用计数,但方法名为CFRetain,CFRelease。
其实就是属于不同的框架,采用了相同的策略,但是没有采用相同命名约定,故而转换一次。

10.数组使用的特别说明
数组分为动态数组和静态数组。静态数组的使用和对象的使用方式相同,数组超过生存周期时,数组中的对象也被释放。(由编译器搞定)
动态数组:采用分配的方式,编译器并不知道该数组的生存周期,所以需要自己手动释放
1.分配方式
NSObject* __strong* arr = nil; //默认为__autoreleasepool
arr = (id __strong*) calloc(num, sizeof(id)); YES
会初始化分配空间为0
arr = (id __strong*) malloc(num*sizeof(id));
初始空间不为0,乱码
当arr[0] = nil; 释放了一个未知的对象非常危险。
所以推荐使用calloc

2.需要手动释放数组的元素,然后再释放数组
    for (int i=0;i<num;i++)
        arr[i] = nil;
    free(arr);
3.memcpy,realloc就不要使用了,导致各种未知的错误。
推荐最好不要使用动态数组
  1. ARC无效的情况下:
    [[NSObject alloc] init]; //错误,生成的对象无人接管,内存泄漏
    (void)[[NSObject alloc] init]; //正确 编译器的解释

12.由于弱引用会注册到autoreleasepool中,当某一变量多次使用的时候,该弱引用会被多次注册到autoreleasepool,所以在使用的时候,可以使用一个强引用等于弱引用,然后一直使用强引用,避免多次注册

13.其它注意事项
1.在使用非ARC时,如果对象有赋值接口时,需先判断接口是否为nil,不为nil时,需先释放原来持有的数据,再进行赋值。并对新对象进行计数
ex:
- (void) setObj:(NSObject*) obj
{
if (_item != nil)
{
[_item release];
_item = obj;
[_item retain];
}
}
- (void) dealloc
{
[_item release];
[super dealloc];
}
2. runloop、autorelease pool以及线程之间的关系
每个线程(包含主线程)都有一个Runloop。对于每一个Runloop,系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个像callstack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值