狮子头镇楼
《Objective-C 高级编程》学习笔记2-Blocks
1、什么是自动引用计数
- 内存管理中对引用采取自动计数的技术
- 在编译器中设置 ARC 为有效状态,就无需再次键入 retain 或者是 release 代码
2、内存管理 / 引用计数
2.1 内存管理的思考方式
- 自己生成的对象,自己所持有
- 非自己生成的对象,自己也能持有
- 不再需要自己持有的对象时释放
- 非自己持有的对象无法释放
2.2 alloc/retaion/release/dealloc 实现
GNUstep 是 Cocoa 框架的互换框架
2.2.1、GNUstep 中 alloc 类方法实现的简化版:
struct obj_layout {
NSUInteger retained;
};
+ (id)alloc {
int size = sizeof(struct obj_layout) + 对象大小;
struct obj_layout *p = (struct obj_layout *)calloc(1, size);
return (id)(p + 1);
}
2.2.2、alloc 返回对象的内存图:
2.2.3、GNUstep 内存管理总结:
- 在 OC 对象中存有引用计数这一整数值
- 调用 alloc 或是 retaion 方法后,引用计数值加1
- 调用 release 后,引用计数值减1
- 引用计数值为0时,调用 dealloc 方法废弃对象
2.3 内存管理-苹果的实现
// __CFDoExternRefOperation 函数按 retainCount/retain/release 操作进行分发调用不同函数
// NSObject 类的相关方法实现如下:
- (NSUInteger)retainCount {
return (NSUInteger)__CFDoExternRefOperation(OPERATION_retainCount, self);
}
- (id)retain {
return (id)__CFDoExternRefOperation(OPERATION_retain, self);
}
- (void)release {
__CFDoExternRefOperation(OPERATION_release, self);
}
GNUstep 将引用计数保存在对象占用内存块头部的变量中,
苹果则是保存在引用计数表的记录中:
通过内存块头部管理引用计数的好处:
- 少量代码即可完成
- 能够统一管理引用计数用内存块与对象用内存块
通过引用计数表管理引用计数的好处:
- 对象用内存块的分配无需考虑内存块头部
- 引用计数表各记录中存有内存块地址,可从各个记录追溯到各对象的内存块
3、ARC 规则
3.1 所有权修饰符
OC 编程中为了处理对象,可将变量类型定义为 id 类型或各种对象类型:
- 对象类型就是指向 NSObject 这样的OC类的指针,例如“NSObject *”
- id 类型用于隐藏对象类型的类名部分,相当于C语言中常用的“void *”
ARC有效时,id类型和对象类型必须附加所有权修饰符:
- __strong
- __weak
- __unsafe_unretained
- __autoreleasing
3.1.1、__strong修饰符:默认的所有权修饰符
__strong修饰符表示对对象的“强引用”。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放。
**3.1.2、__weak修饰符:避免引用循环,**弱引用不能持有对象实例
循环引用容易造成内存泄漏,内存泄漏就是应当废弃的对象在超出其生存周期后继续存在。
__weak修饰符,在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于nil被赋值的状态。
3.1.3、__unsafe_unretained修饰符:在iOS以下中用来代替__weak
附有__unsafe_unretained修饰符的变量不属于编译器的内存管理对象
赋值给附有__unsafe_unretained修饰符变量的对象在通过该变量使用时,如果没有确保其确实存在,则应用程序会崩溃。
3.1.4、__autoreleasing修饰符
ARC有效时,指定“@autoreleasepool块”替代“NSAutoreleasePool”类,用附有 __autoreleasing 修饰符的变量替代 autorelease 方法。
不使用 __autoreleasing 修饰符也能使对象注册到 autoreleasepool。由于return使强引用持有的对象超出作用域会被释放,但该对象作为函数的返回值,编译器会自动将其注册到 autoreleasepool。
在访问附有 __weak 修饰符的变量时,实际上必定要访问注册到 autoreleasepool 的对象。
3.2 规则
在 ARC 有效的情况下编译源代码,必须遵守一定的规则:
- 不能使用 retain/release/retainCount/autorelease
- 不能使用 NSAllocateObject/NSDeallocateObject
- 须遵守内存管理的方法命名规则
- 不要显示调用 dealloc
- 使用 @autoreleasepool 块替代 NSAutoreleasePool
- 不能使用区域(NSZone)
- 对象型变量不能作为C语言结构体的成员
- 显示转换“id” 和 “void *”
3.2.3、ARC 有效时须遵守内存管理的方法命名规则
在 ARC 无效时,用于对象 生成/持有 的方法必须遵守命名规则:
- alloc
- new
- copy
- mutableCopy
在 ARC 有效时,以上规则没有改变。只是要追加一条命名规则:
- init,该方法会初始化 alloc 方法返回的对象,然后原封不动地返还给调用方
3.3 属性
当 ARC 有效时,Objective-C 类的属性也会发生变化: