前言
因為自己開始iOS開發(fā)的時候已經(jīng)是RAC時代距芬,所以對MRC了解僅僅是一些表面,具體的一些retain框仔、autorelease字段的應(yīng)用則是少之又少,也沒想著做一些補充银舱。知道前陣子去面試跛梗,被一個面試官一直問MRC以及內(nèi)存管理的一些問題,把我問的頭皮發(fā)麻茄袖。終于,下定決心聂薪,透徹的學(xué)習(xí)一下iOS的內(nèi)存管理蝗羊,以及Block,深思熟慮之后耀找,選擇了這本《Objective-C高級編程(iOS與OS X多線程和內(nèi)存管理)》。
自動引用計數(shù)
首先來說明一下內(nèi)存管理的思考方式:
- 自己生成的對象蓄愁,自己持有狞悲。
- 非自己生成的對象,自己也能持有摇锋。
- 不再需要自己持有的對象時釋放。
- 非自己持有的對象無法釋放乖酬。
標(biāo)題 | 標(biāo)題 |
---|---|
生成并持有對象 | alloc/new/copy/mutableCopy |
持有對象 | retain |
釋放對象 | release |
放棄對象 | dealloc |
autorelease
自動釋放,類似于C語言中的自動變量媳纬。
作用:
- 生成并持有
NSAutoreleasePool
對象 - 調(diào)用已分配的對象autorelease實例方法
- 飛起NSAutoreleasePool對象
NSAutoreleasePool *pool = [NSAutoreleasePool new];
id obj = [NSObject new];
[obj autorelease]; //obj加入到指定的緩存釋放池中
[pool drain]; //相當(dāng)于調(diào)了release
retain
引用計數(shù)+1施掏,并且持有當(dāng)前對象。
id obj = [NSMutableArray array]; //聲明但并沒有持有
[obj retain]; //持有對象
聲明不持有對象的優(yōu)化
+ (id)array
{
return [[NSMutableArray alloc] init];
}
+ (id)array
{
id obj = objc_msgSend(NSMutableArray,@selector(alloc));
obj_msgSend(obj,@selector(init));
return objc_autoreleaseReturenValue(obj);
}
通過objc_autoreleaseReturnValue
和objc_retainAutoreleaseValue
兩個方法避免對象注冊到autoreleasepool
中而直接傳遞素挽,這一過程達到優(yōu)化.
Blocks
Blocks實質(zhì)是一個結(jié)構(gòu)體狸驳,里面有對應(yīng)的isa
指針,以及函數(shù)指針耙箍。
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock; //對應(yīng)的類型
impl.Flags = flags;
impl.FuncPtr = fp; //代碼塊地址
Desc = desc;
}
};
由上述代碼可知,block
其實也是有自己的類型的阅酪,共有三種:
- _NSConcreteGlobalBlock
- _NSConcreteStackBlock
- _NSConcreteMallocBlock
_NSConcreteGlobalBlock全局block沒什么可說的汁针,就是在全局聲明的block,存在數(shù)據(jù)段施无。
_NSConcreteStackBlock棧區(qū)block,在局部聲明瑞躺,聲明周期與當(dāng)前{}相同兴想,一般可做一次copy
拷貝到堆中。
_NSConcreteMallocBlock堆區(qū)block襟企,可供持有者任意調(diào)動。
__block說明符
先看段代碼
id obj = [NSMutableArray new];
void(^block)(id obj)
{
[obj addObject:obj];
NSLog("%ld",obj.count);
}
block([NSObject new]);
id obj = [NSMutableArray new];
void(^block)(void)
{
obj = [NSMutableArray new];
}
第一段代碼執(zhí)行沒有問題曼振,new
的對象存儲在堆區(qū)蔚龙,addObject:
方法是對obj
指向的堆區(qū)做操作,縮一沒問題木羹。
第二段代碼會報錯,obj
是存在棧區(qū)的自動變量抛人,如果想在block
內(nèi)改變棧區(qū)變量的值脐瑰,需要通過一個__block
修飾符。
__block內(nèi)部的實現(xiàn)
struct __Block_byref_b_0 {
void *__isa;
__Block_byref_b_0 *__forwarding;
int __flags;
int __size;
int b;
};
__block
修飾的變量對應(yīng)的有一個結(jié)構(gòu)體绝页,當(dāng)棧區(qū)的block訪問__block
變量時寂恬,__forwarding
扔指向自己,當(dāng)棧區(qū)的block
被拷貝到了堆區(qū)初肉,那么__block
變量會跟著一起拷貝到堆區(qū)一份,這是__forwarding
指針指向堆區(qū)的自己井佑,并且這個變量被block
持有.__block
變量既能被堆區(qū)的block
截獲眠寿,也能被棧區(qū)的block
截獲就是通過__forwarding
實現(xiàn)的。
GCD
本書GCD只是簡介的介紹了一下一些API的作用盯拱,沒有太多的用法,以及深度解析宁舰。