《Objective-C高级编程》---笔记---ARC

ARC

ARC(Automatic Reference Counting),自动引用计数器
是指内存管理中对引用采取 自动计数的技术。

在OC中,采用ARC机制,让编译器来进行内存管理。

  • 自己生成的对象,自己所持有
  • 非自己生成的对象,自己也能持有
  • 不再需要自己持有的对象,释放
  • 非自己持有的对象无法释放

在这里插入图片描述
OC内存管理中的alloc/retain/release/dealloc 方法分别指代:
NSObject 类的alloc 类方法、retain 实例方法、release 实例方法和 dealloc 实例方法。

autorelease提供这样的功能:使对象在超出指定的生存范围时,能够自动并正确地释放(调用release方法)

release与autorelease的区别

release与autorelease的区别

  • 当引用计数器等于0时,调用dealloc实例方法

autorelease

autorelease就是自动释放池
autorelease的具体使用方法如下:

  1. 生成并持有NSAutoreleasePool对象
  2. 调用已分配对象的autorelease实例方法
  3. 废弃NSAutoreleasePool对象

NSAutoreleasePool对象的生命周期:
在这里插入图片描述

问:MRC中有自动释放池吗?MRC中有autorelease吗?


MRC有自动释放池,有autorelease
ARC只是在编译阶段,遇到需要添加autorelease的地方,自动添加上,不需要手动添加而已

问:在MRC中,调用如下代码会如何:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[pool autorelease];

Crash
在这里插入图片描述
在ARC中,id类型和对象类型同C语言其他类型不同,其类型上必须附加所有权修饰符

也就是,对象类型前面,必须有所有权修饰符

所有权修饰符有4种
__strong修饰符
__weak修饰符
__unsafe_unretained修饰符

__strong修饰符

__strong修饰符是对象的默认修饰符
id obj = [[NSObject alloc] init]
其实是:
id __strong obj = [[NSObject alloc] init]

__strong、__weak、__autoreleasing都可以保证将附有这些修饰符的自动变量初始化为nil

id __strong obj0;
id __weak obj1;
id __autoreleaing obj2;

id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleaing obj2 = nil;

相同

__weak修饰符

__weak修饰符避免了循环引用问题,并且可以在该对象被废弃的时候,弱引用将自动失效且处于nil被赋值的状态

__unsafe_unretained修饰符

ARC的内存管理是编译器的工作,但附有__unsafe_unretained修饰符的变量不属于编译器的内存管理对象。

附有__unsafe_unretained修饰符的变量,同附有__weak修饰符的变量一样,因为自己生成并持有的对象不能继续为自己所有,所以生成的对象会立即被释放。
与__weak不同的是,在对象被废弃的时候,不会主动被赋值为nil,再访问容易造成悬垂指针。

__autoreleasing修饰符

在ARC中,不允许使用autorelease方法,也不能使用NSAutoreleasePool类。
虽然程序员无法直接使用,但实际上,ARC的autorelease功能是起作用的

MRC下:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];

ARC下:

@autoreleasepool {
	id _autoreleaseing obj = [[NSObject alloc] init];
}

使用 ”@autoreleasepool块“ 来替代 ”NSAutoreleasePool类对象生成、持有以及废弃“ 这一范围。

在这里插入图片描述

ARC下,通过将对象赋值给附加了__autoreleasing修饰符的变量来替代调用autorelease方法(MRC下的[obj autorelease])。这一就完成了对象被注册到autoreleasepool

取得非自己生成并持有的对象时,ARC下,编译器会检查方法名是否以alloc/new/copy/mutableCopy开始,如果不是,则自动将返回值的对象注册到autoreleasepool

举个例子

id __strong obj = [NSMutableArray array];

编译器判断其方法名后,自动注册到autoreleasepool

@autoreleasepool {
	id __strong obj = [NSMutableArray array];
}

在这里插入图片描述

init方法返回值的对象不注册到autoreleasepool


使用ARC需要遵守的规则

ARC编译代码时,需要遵守的规则:

  • 不能使用 retain/release/retainCount/autorelease
  • 不能使用 NSAllocateObject/NSDeallocateObject
  • 须遵守内存管理的方法命名规则
  • 不要显式调用 dealloc
  • 使用 @autoreleasepool 块替代 NSAutoreleasePool
  • 不能使用区域 (NSZone)
  • 对象型变量不能作为 C 语言结构体 (struct/union)的成员
  • 显式转换“id”和“void *”

在ARC下,以init方法创建的对象,不注册到autoreleasepool上。
init方法的作用,基本上只是对alloc方法返回值的对象进行初始化处理,并返回该对象

对象被废弃时,不管ARC还是MRC,都会调用对象的dealloc方法

C语言的结构体成员中,如果存在OC对象型变量,便会引起编译错误。


属性

在这里插入图片描述


ARC的实现

ARC由LLVM编译器运行时来实现

{
	id __strong obj = [[NSObject alloc] init];
}

编译后的模拟代码:

id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);

由此可见:
变量作用域结束时通过objc_release释放对象。
编译器自动插入了release。

{
	id __weak obj1 = obj;
}

编译后的模拟代码:

id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1);

释放对象时,废弃谁都不持有的对象的同时,程序的动作是怎么的呢?
对象通过objc_release函数释放。

  1. objc_release
  2. 因为引用计数为0,所以执行dealloc
  3. _objc_rootDealloc
  4. object_dispose
  5. objc_destructInstance
  6. objc_clear_deallocating

对象被废弃时,最后调用的objc_clear_deallocating函数的动作如下:

  1. 从weak表中获取废弃对象的地址为键值的记录
  2. 将包含在记录中的所有附有__weak修饰符变量的地址,赋值为nil
  3. 从weak表中删除该记录
  4. 从引用计数表中删除废弃对象的地址为键值的记录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值