1.2.2
內(nèi)存管理原則:
- 自己生成的對象,自己所持有
- 非自己生成的對象,自己也能持有
- 不再需要自己持有的對象時釋放
- 非自己持有的對象無法釋放
自己生成的對象,自己所持有
//自己生成并持有對象
id obj = [[NSObject alloc] init];
//自己持有對象
使用NSObject類的alloc類方法就能自己生成并持有對象。指向生成并持有對象的指針
使用一下名稱開頭的方法名意味著自己生成的對象只有自己持有:
- alloc
- new
- copy
- mutableCopy
根據(jù)以上規(guī)則,下列名稱也意味著自己生成并持有對象
- allocMyObject
- newThatObject
但是以下規(guī)則無效 - allocate
- newer
非自己生成的對象,自己也能持有
//非自己生成并持有的對象
id obj = [NSMutableArray array];
//取得的對象存在,但自己不持有對象
源碼中,NSMutableArray類對象唄賦值給變量obj,但變量obj自己并不持有該對象。使用retain方法可以持有對象
//在后面多加一句
[obj retain];
//自己持有對象
不再需要自己持有的對象時釋放
釋放時使用release方法
//自己生成并持有對象
id obj = [[NSObject alloc] init];
//自己持有對象
[obj release];
//釋放對象。指向?qū)ο蟮闹羔樔稳槐槐A粼谧兞縪bj中,貌似能夠訪問
//但是對象一經(jīng)釋放絕對不可訪問
如果要用某個方法生成對象,并將其返還給該方法的調(diào)用方,那么它的源代碼又是怎樣的呢
-(id)allocObject
{
//自己生成并持有對象
id obj = [[NSObject alloc] init];
//自己持有對象
return obj;
}
如上,原封不動的返回用alloc方法生成并持有的對象,就能讓調(diào)用方也持有改對象。請注意allocObject這個名稱是符合前文命名規(guī)則的
//取得非自己生成并持有的對象
id obj1 = [ojb0 allocObject];
//自己持有對象
所以,如果要自己不持有對象,就不能使用alloc/new/copy/mutableCopy開頭的方法名,實現(xiàn)如下
-(id)object
{
id obj = [[NSObject alloc] init];
//自己持有對象
[obj autorelease];
//取得對象存在,但自己不持有
return obj;
}
上例中,我們使用了autorelease方法,該方法可以取得對象存在,但自己不持有對象。autorelease提供使得對象在超出指定的生存范圍時能夠自動并正確得釋放的功能
??當然,也能夠通過retain方法將調(diào)用autorelease方法取得的對象變?yōu)樽约撼钟?/p>
id obj1 = [obj0 object];
//取得但自己不持有
[obj1 retain];
//自己持有對象
無法釋放非自己持有的對象
id obj = [[NSObject alloc] init];
[obj release];
[obj release];
//這里這里就崩潰了
id obj1 = [obj0 object];
[obj1 release];
//這里也崩潰
1.3.3所有權(quán)修飾符
__strong
ARC時,id類型的對象類型同C語言其他類型不同,其類型上必須附加所有權(quán)修飾符。所有權(quán)修飾符一共有4種
__strong __weak __unsafe __unretained __autoreleasing
__strong修飾符是id類型的和對象類型默認的所有權(quán)修飾符。也就是說,以下源代碼中的id變量,實際上被附加了所有權(quán)修飾符
id obj = [[NSObject alloc] init];
其與以下相同
id __strong obj = [[NSObject alloc] init];
MRC下:
id obj = [[NSObject alloc] init];
再看以下代碼
{
id __strong obj = [[NSObject alloc] init];
}
MRC下:
{
id obj = [[NSObject alloc] init];
[obj release];
}
為了釋放生成并持有的對象,增加了release方法的代碼
如此源碼所示,附有__strong修飾符的變量obj在超出其變量作用域時,即在該變量被廢棄時,會釋放其被賦予的對象
__strong、__weak、__autoreleasing,可以保證附有這些修飾符的自動變量初始化為nil
id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;
同:
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;
id __weak obj = [[NSObject alloc] init];
NSLog(@"弱引用自身地址:%p",&obj);
NSLog(@"弱引用指向地址:%p",obj);
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
NSLog(@"強引用自身地址:%p",&obj0);
NSLog(@"弱引用自身地址:%p",&obj1);
NSLog(@"強引用指向地址:%p",obj0);
NSLog(@"弱引用指向地址:%p",obj1);
// obj1 = nil;
// obj0 = nil;
NSLog(@"弱引用銷毀時強類型變量指向地址:%p",obj0);
NSLog(@"弱引用銷毀時弱類型變量指向地址:%p",obj1);

由此可見,強引用時對變量擁有,弱引用時只是指向該變量而不擁有
非自己生成的對象,即alloc/new/copy/mutableCopy以外的創(chuàng)建方法取得對象,并且賦值給非strong變量時,對象將會自動注冊至autoreleasepool,從而不至于立刻被析構(gòu); (3.1)
當賦值給給strong變量時,編譯器作自動優(yōu)化插入objc_retainAutoreleaseedReturnValue, 而不是插入retain,以避免注冊至autoreleasePool.(3.3)
訪問weak變量時,將會把指向?qū)ο笞灾羇utoreleasePool.(3.3)。另外,對weak變量再訪問會再注冊,訪問幾次則會注冊幾次,所以這里,最好把weak變量賦給一個strong變量,避免重復注冊到aotureleasepool
獲取引用計數(shù)數(shù)值的函數(shù)uintptr_t objc_rootRetainCount(id obj)
例子:
{
id __strong obj = [[NSObject alloc] init];
id __weak o = obj;
NSLog(@"retain count = %d", _objc_rootRetainCount(obj));//結(jié)果為1
}
dispatch_sync函數(shù)。它意味著“同步”,也就是將制定Block“同步”追加到指定的Dispatch Queue中。在追加Block結(jié)束之前,dispatch_sync函數(shù)會一直等待
sync引起線程死鎖
sync 會等到 后面block 執(zhí)行完成才返回, sync 又再 dispatch_get_main_queue() 隊列中,
它是串行隊列,sync 是后加入的,前一個是主線程,
所以 sync 想執(zhí)行 block 必須等待主線程執(zhí)行完成,主線程等待 sync 返回,去執(zhí)行后續(xù)內(nèi)容。
dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"=================2"); });
以下正面例子
- (void)viewDidLoad{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"=================1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"=================2"); });
NSLog(@"=================3"); });
}
程序會完成執(zhí)行,為什么不會出現(xiàn)死鎖。
首先: async 在主線程中 創(chuàng)建了一個異步線程 加入 全局并發(fā)隊列,async 不會等待block 執(zhí)行完成,立即返回,
1,async 立即返回, viewDidLoad 執(zhí)行完畢,及主線程執(zhí)行完畢。2,同時,全局并發(fā)隊列立即執(zhí)行異步 block , 打印 1, 當執(zhí)行到 sync 它會等待 block 執(zhí)行完成才返回, 及等待
dispatch_get_main_queue() 隊列中的 mianThread 執(zhí)行完成, 然后才開始調(diào)用block 。因為1 和 2 幾乎同時執(zhí)行,因為2 在全局并發(fā)隊列上, 2 中執(zhí)行到sync 時 1 可能已經(jīng)執(zhí)行完成或 等了一會,mainThread 很快退出, 2 等已執(zhí)行后續(xù)內(nèi)容。