中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Objective-C中內存管理的一些特例

發布時間:2020-06-25 07:30:57 來源:網絡 閱讀:696 作者:hailinan 欄目:移動開發

 

     該教程是討論IOS平臺上內存管理規則之外的一些特殊情況,我相信大部分的開發人員可能都沒有覺察到。

    我們先普及一下Objectivie-C中的內存管理的基本知識,如果你已經比較熟悉了,可以直接跳過該節。Objective-C使用的是引用計數(Reference Counting),引用計數就是對象用一個變量來保存有幾個地方(類、方法等)在使用它。當一個對象被創造出來時,它的引用計數(下面我們用retainCount來表示這個值)為1,在應用程序運行的過程中,可能有很多地方都用到了這個對象,凡是用到這個對象時,就將它的retainCount加1,當不用了時,再將其retainCount減1,當對象的retainCount為0時,表示沒有人在用這個對象了,系統就會釋放這個對象所占用的內存。

在Objective-C中,關于基于引用計數的內存管理,其實你只需要掌握三條最基本的規則:
  • 當你使用new、alloc或copy方法創建一個對象時,對象的引用計數值為1.當不再使用該對象時,你要負責向該對象發送一條release或autorelease消息。這樣該對象會在其使用壽命結束時被銷毀。
  • 當你通過其它方法獲得一個對象時,則假設該對象的保留計數值為1, 而且已經被設置為自動釋放,你不需要執行任何操作來確保該對象被清理。但是如果你打算在一段時間內擁有該對象,則需要保留(引用計數加1)它,并且在操作完成時釋放它(引用計數減1)。
  • 如果你保留了某個對象,你需要最終釋放或者自動釋放該對象,必須保持保留方法(retain)和釋放方法(release/autorelease)的使用次數相等。
    只要你理解了這三條規則基本就足夠了。但是要理解下面所講的一些例外情況,僅有這些知識就不夠了。下面就讓我們開始這段探索之旅吧。
 
使用Xcode使用“IOS”-“Application”-“Single View Application”模板創建一個名為MemoryTest的工程。在ViewController.m文件的viewDidLoad方法中鍵入下面的代碼:
  1. NSString *emptyStr = [NSString new];  
  2. NSLog(@"emptyStr retainCount: %u", emptyStr.retainCount); 
先想想你認為輸出結果是什么?然后看一下運行后Console的輸出是什么?我這邊的結果是4294967295,一個很大的數,實際上這個數是UINT_MAX,就是無符號整型的最大值。你原先認為它應該輸出1對嗎?為什么會這樣呢?帶著這個疑問在看下面的代碼,仍舊將其放入viewDidLoad方法中:
 
  1. NSString *emptyStr1 = [NSString new]; 
  2. NSString *emptyStr2 = [NSString new]; 
  3. NSLog(@"emptyStr1 address: %p", emptyStr1); 
  4. NSLog(@"emptyStr2 address: %p", emptyStr2); 
  5. NSLog(@"emptyStr1 retainCount: %u", emptyStr1.retainCount); 
  6. NSLog(@"emptyStr2 retainCount: %u", emptyStr2.retainCount); 
這段代碼創建了兩個新的空字符串對象,接著輸出這兩個對象的在內存中的地址和它們的引用計數值。運行一下,查看一下結果,我這邊的結果是:

       Objective-C中內存管理的一些特例

這兩個對象的地址竟然一樣,這出離我們原先的認識對嗎?new方法兩次創建的對象竟然一樣,這在c++中是絕不可能的。但這是Objective-C,編譯器在底層做了一些我們看不見的工作。很顯然這兩個空字符串對象指針指向的是同一個對象。Objective-C為什么會這么處理呢?這是因為NSString類型的不可變性,就是這種類型的對象一旦創建,就不能改變(增加或刪除其中的字符),如果你希望改變對象,那就用NSMutableString類型。NSString的不可變性使得空字符串對象一旦創建,就不能改變,永遠是空字符串,而所有的空字符串都是一樣的。所以出于效率的考量,Objective-C編譯器在底層就讓所有創建的空字符串指向內存中的同一個空字符串。并且這個空字符串對象是不可release掉的,因此它的引用計數值就為UINT_MAX,表示這個對象是不可release的,那你可能會問,我如果release UINT_MAX次,是不是就釋放掉了,不是的,實際上你向這個對象發送release消息是沒有任何效果的。
 我們換非空字符串試試,輸入下面的代碼:
  1. NSString *nonEmptyStr1 = @"Hello"; 
  2. NSString *nonEmptyStr2 = [[NSString alloc] initWithString:@"Hello"]; 
  3. NSString *nonEmptyStr3 = [[NSString alloc] initWithFormat:@"%@", @"Hello"]; 
  4. NSLog(@"nonEmptyStr1 address: %p", nonEmptyStr1); 
  5. NSLog(@"nonEmptyStr2 address: %p", nonEmptyStr2); 
  6. NSLog(@"nonEmptyStr3 address: %p", nonEmptyStr3); 
  7. NSLog(@"nonEmptyStr1 retainCount: %u", nonEmptyStr1.retainCount); 
  8. NSLog(@"nonEmptyStr2 retainCount: %u", nonEmptyStr2.retainCount); 
  9. NSLog(@"nonEmptyStr3 retainCount: %u", nonEmptyStr3.retainCount); 
下面是在機器上運行結果:

       Objective-C中內存管理的一些特例

前兩個指針仍然是指向同一個對象,原因上面已經解釋了。但是第三個不一樣,你可以從NSString的不可變性和對象的初始化方式的不同出發想想原因,相信你很快就可以得出結論的。
在Objective-C中不唯NSString是不可變對象,還有NSArray和NSDictionary。同樣你可以試試下面的代碼:
 
  1. NSArray *emptyArray1 = [[NSArray alloc] init]; 
  2. NSArray *emptyArray2 = [[NSArray alloc] init]; 
  3. NSArray *emptyArray3 = [[NSArray alloc] initWithArray:emptyArray1]; 
  4. NSLog(@"emptyArray1 address: %p", emptyArray1); 
  5. NSLog(@"emptyArray2 address: %p", emptyArray2); 
  6. NSLog(@"emptyArray3 address: %p", emptyArray3);     
  7. NSLog(@"emptyArray1 retainCount: %d", emptyArray1.retainCount); 
  8. NSLog(@"emptyArray2 retainCount: %d", emptyArray2.retainCount); 
  9. NSLog(@"emptyArray3 retainCount: %d", emptyArray3.retainCount); 
  10.  
  11. NSArray *nonEmptyArray1 = [[NSArray alloc] initWithObjects:@"1", @"2", nil]; 
  12. NSArray *nonEmptyArray2 = [[NSArray alloc] initWithObjects:@"1", @"2", nil]; 
  13. NSLog(@"nonEmptyArray1 address: %p", nonEmptyArray1); 
  14. NSLog(@"nonEmptyArray2 address: %p", nonEmptyArray2); 
  15. NSLog(@"nonEmptyArray1 retainCount: %d", nonEmptyArray1.retainCount); 
  16. NSLog(@"nonEmptyArray2 retainCount: %d", nonEmptyArray2.retainCount); 
  17.  
  18. NSDictionary *emptyDict1 = [[NSDictionary alloc] init]; 
  19. NSDictionary *emptyDict2 = [[NSDictionary alloc] init]; 
  20. NSLog(@"emptyDict1 address: %p", emptyDict1); 
  21. NSLog(@"emptyDict2 address: %p", emptyDict2); 
  22. NSLog(@"emptyDict1 retainCount: %d", emptyDict1.retainCount); 
  23. NSLog(@"emptyDict2 retainCount: %d", emptyDict2.retainCount); 
通過運行結果來進一步體會一下Objective-C編譯器底層的工作機理。
按照上面提到過的三條內存管理規則,你new、init、copy得到一個對象,你就必須負責release掉它,但實際上前面提到過的這些語句是個例外:
 
  1. NSString *s1 = [NSString new]; 
  2. NSString *s2 = [NSString alloc] initWithString:@"Hello"]; 
  3. NSArray *a = [NSArray alloc] init];  
  4. NSDictionary *dict = [NSDictionary alloc] init]; 

就算你不調用release或autorelease方法釋放也不會造成內存泄漏,你可以用Instruments檢測一下看看是否有內存泄漏。但是雖然如此,我仍強烈建議你按照內存管理三規則來處理。一致的規則不容易讓人迷惑,尤其是對閱讀你代碼的人。
 
本教程的工程文件:MemoryTest.zip
 
本文作者:安海林,軟件工程師,諾基亞北京研究院。他的格言是:學問深時意氣平!

  

附件:http://down.51cto.com/data/2360642
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

平罗县| 罗平县| 大余县| 宜兰县| 浦县| 淮阳县| 四川省| 开远市| 凯里市| 铜梁县| 荣昌县| 淮阳县| 阿城市| 清苑县| 苗栗市| 神农架林区| 常熟市| 青海省| 怀宁县| 黄陵县| 通辽市| 大竹县| 苏尼特右旗| 樟树市| 奉化市| 淳安县| 墨江| 综艺| 博乐市| 贵港市| 云霄县| 塔河县| 甘泉县| 九龙坡区| 盘山县| 洛宁县| 建瓯市| 德兴市| 晋州市| 六枝特区| 罗定市|