Objective-C 內(nèi)存管理基礎(chǔ)

前言

之前的兩篇拙文C語言-內(nèi)存管理基礎(chǔ)C語言-內(nèi)存管理深入 介紹了關(guān)于C語言在內(nèi)存管理方面的相關(guān)知識(shí)。但是對于從事iOS開發(fā)的同胞們來說,顯然Objective-C用的更多,所以筆者想用兩篇文章盡量完整的介紹一下Objective-C的內(nèi)存管理,本文為第一部分,將從類和對象所有權(quán)策略及引用計(jì)數(shù)機(jī)制、內(nèi)存管理原則、內(nèi)存管理方式等幾個(gè)方面展開。如果你能賞臉閱讀此文,你會(huì)發(fā)現(xiàn)本文利用近一半的篇幅介紹ObjC對象的相關(guān)知識(shí),這是因?yàn)镺bjective-C內(nèi)存管理-管理的是繼承自NSObject的對象的內(nèi)存。閱讀本文要求讀者對C語言內(nèi)存管理有一定的了解,尚不熟悉的同學(xué)請移步到這里:C語言-內(nèi)存管理基礎(chǔ)。話不多說,先附上本文內(nèi)容的思維導(dǎo)圖。

主要內(nèi)容思維導(dǎo)圖

類的結(jié)構(gòu)與加載過程

Objective-C作為一門擴(kuò)充C的面向?qū)ο缶幊陶Z言,其和C語言的區(qū)別之一在于引入“面向?qū)ο蟆彼枷?,能夠靈活的使用類和對象進(jìn)行編程。因此了解類的結(jié)構(gòu)和本質(zhì)對于學(xué)習(xí)Objective-C是非常重要的。

  • 類的結(jié)構(gòu)
    Objective-C中的類是本身也是一個(gè)Class類型的對象,簡稱類對象。而Class實(shí)際上是一個(gè)指向objc_class結(jié)構(gòu)體的指針。
typedef struct objc_class *Class;

通過查看 objc/runtime.h文件,得知objc_class結(jié)構(gòu)組成,其中包括了一個(gè)類很多信息。

struct objc_class {
  Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
  Class super_class                       OBJC2_UNAVAILABLE;  // 父類
  const char *name                        OBJC2_UNAVAILABLE;  // 類名
  long version                            OBJC2_UNAVAILABLE;  // 類的版本信息,默認(rèn)為0
  long info                               OBJC2_UNAVAILABLE;  // 類信息,供運(yùn)行期使用的一些位標(biāo)識(shí)
  long instance_size                      OBJC2_UNAVAILABLE;  // 該類的實(shí)例變量大小
  struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 該類的成員變量鏈表
  struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定義的鏈表
  struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法緩存
  struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 協(xié)議鏈表
#endif
} OBJC2_UNAVAILABLE;
ObjC對象結(jié)構(gòu)圖
  • 獲取內(nèi)存中的類對象
  • 利用類的class方法
    【函數(shù)原型】+ (Class)class
    【方法說明】類方法,通過特定的一個(gè)類調(diào)用該方法返回一個(gè)Class類型的類對象。
Class classP = [Person class]; //classP現(xiàn)在一個(gè)`Class `類型的類對象
  • 利用類的實(shí)例對象的class方法
    【函數(shù)原型】- (Class)class
    【方法說明】對象方法,通過某個(gè)類的實(shí)例對象調(diào)用該方法返回一個(gè)Class類型的類對象。
Person *objectP = [[Person alloc] init];
Class classP1 = [objectP class];

可以利用objectP類對象創(chuàng)建Person類的實(shí)例對象,并通過打印確定classPPerson類型。

Person *objectP1 = [[classP new] init];
NSLog(@"%@", NSStringFromClass(classP)); 

控制臺(tái)輸出:

//2017-02-05 15:49:57.916948 類和對象[4473:131075] Person

打印classP、classP 1內(nèi)存地址發(fā)現(xiàn)數(shù)值相同,說明類在內(nèi)存中只有一份。

NSLog(@"%p, %p",classP, classP1);
// 2017-02-05 15:28:53.340127 類和對象[4238:123830] 0x1000011e0, 0x1000011e0
  • 類的加載和初始化
  • 類的加載
    【函數(shù)原型】+ (void)load
    【函數(shù)說明】 程序運(yùn)行把Xcode的"Compile Sources"選項(xiàng)中存在的類和分類(不管有沒有用到)加載進(jìn)來時(shí)調(diào)用,先調(diào)用父類再調(diào)用子類,每個(gè)類調(diào)用一次。
  • 類的初始化
    【函數(shù)原型】+ (void)initialize
    【函數(shù)說明】第一次使用到該類時(shí)調(diào)用。優(yōu)先調(diào)用該類分類中的initialize方法,子類調(diào)用時(shí)會(huì)先調(diào)用父類的initialize方法初始化父類。

【區(qū)別】:load方法類和分類都會(huì)調(diào)用,因?yàn)樗麄兪欠珠_加載的,分類的加載順序和編譯順序有關(guān);initialize方法是首次使用到該類時(shí)調(diào)用,調(diào)用順序是先調(diào)用該類分類中initialize,再調(diào)用該類父類分類的initialize;如果沒有會(huì)調(diào)用該類的initialize,再調(diào)用父類的initialize。


對象的創(chuàng)建

Objective-C中創(chuàng)建對象,先調(diào)用類的alloc方法返回對象再調(diào)用對象的initinitWithSomething方法返回自己亦或是直接調(diào)用該類的new方法。例如下面代碼:

  Person *p1 = [[Person alloc] init];
  Person *p2 = [Person new];

依次介紹下面三個(gè)方法:

  • + (instancetype) alloc
    該方法被調(diào)用時(shí)系統(tǒng)首先在堆區(qū)分配合適大小的內(nèi)存存儲(chǔ)該對象(參考C語言-內(nèi)存管理基礎(chǔ)-C語言操作堆內(nèi)存的函數(shù)部分內(nèi)容),并返回一個(gè)未被初始化的該類型的對象,并完成下面三件事情:(引自談ObjC兩段構(gòu)造模式

1,將該新對象的引用計(jì)數(shù) (Retain Count) 設(shè)置成 1。
2,將該新對象的 isa 成員變量指向它的類對象。
3,將該新對象的所有其它成員變量的值設(shè)置成零。(根據(jù)成員變量類型,零有可能是指 nil 或 Nil 或 0.0)

  • - (instancetype) init
    根據(jù)對象具體成員變量的類型真正初始化對象的成員變量的值。

  • + (instancetype) new
    可以簡單的理解為將 alloc、init合并為一次操作。

  • 對象的存儲(chǔ)
    上述創(chuàng)建p1、p2的代碼可以解讀為:
  • 系統(tǒng)在內(nèi)存的棧區(qū)分別開辟空間存儲(chǔ)p1p2指針變量
  • 系統(tǒng)在內(nèi)存的堆區(qū)分別開辟空間存儲(chǔ)兩個(gè)Person對象并使棧區(qū)的p1、p2指針變量分別指向堆區(qū)的Person對象。
    對象存儲(chǔ)簡單圖解

對象的所有權(quán)及引用計(jì)數(shù)

  • 所有權(quán)策略:任何自己創(chuàng)建的對象都?xì)w自己所有且都存在一個(gè)或多個(gè)所有者,只要對象至少存在一個(gè)所有者,該對象就不會(huì)被銷毀,其占用的內(nèi)存空間就會(huì)一直存在不被釋放(除非整個(gè)程序已經(jīng)退出)。類似于一瓶礦泉水可能被一個(gè)或多個(gè)人飲用,只要還有一個(gè)人需要飲用該礦泉水,它就不會(huì)被環(huán)衛(wèi)工人回收。
    通過NSObject協(xié)議中的retainCount屬性可以獲得該對象當(dāng)前的引用計(jì)數(shù)值。

  • 引用計(jì)數(shù)器:Cocoa采用一種引用計(jì)數(shù)機(jī)制,為每個(gè)對象都綁定一個(gè)NSUInteger類型的整數(shù)表示該對象當(dāng)前被引用的次數(shù)(即當(dāng)前共有多少個(gè)所有者引用著該對象),稱之為該對象的引用計(jì)數(shù)器。每個(gè)ObjC對象都有自己的引用計(jì)數(shù)器(在64位編譯器環(huán)境下占用8個(gè)字節(jié)空間)。類似于一個(gè)整數(shù)記錄一瓶礦泉水當(dāng)前被多少個(gè)人飲用,當(dāng)該礦泉水沒有被人飲用時(shí)就要被環(huán)衛(wèi)工人回收再利用了。

  • 引用計(jì)數(shù)器的作用:對象剛被創(chuàng)建時(shí)其引用計(jì)數(shù)默認(rèn)為1,當(dāng)對象的引用計(jì)數(shù)器值變?yōu)?時(shí)(即已經(jīng)沒有所有者引用該對象),系統(tǒng)銷毀該對象,釋放并重新利用該對象在堆區(qū)對應(yīng)分配的存儲(chǔ)空間。系統(tǒng)通過判斷對象的引用計(jì)數(shù)器值是否為0來決定是否需要銷毀該對象并釋放其占用的內(nèi)存空間。
    一種例外情況:若對象值為nil時(shí)其引用計(jì)數(shù)為0但系統(tǒng)不回收空間,因?yàn)橄到y(tǒng)尚未為該對象分配空間。

Person *p1 = nil;
 NSLog(@"%lu", (unsigned long)p1.retainCount); //p1.retainCount = 0
  • 與引用計(jì)數(shù)相關(guān)的操作
  • - (instancetype)retain:使對象的引用計(jì)數(shù)器值+1
  • - (oneway void)release:使對象的引用計(jì)數(shù)器值-1(不代表銷毀該對象)
  • - (NSUInteger)retainCount:獲得對象當(dāng)前的引用計(jì)數(shù)器值
  • - (instancetype)autorelease:待稍后清理“自動(dòng)釋放池”(@autoreleasepool)時(shí),再減少對象的引用計(jì)數(shù)

值得注意的是:retain操作無法使一個(gè)已經(jīng)被釋放的對象的引用計(jì)數(shù)器值+1,這也很好理解,retain無法讓一個(gè)已經(jīng)死去的人起死回生,就像環(huán)衛(wèi)工人已經(jīng)回收了你的礦泉水瓶,那么你將不能再持有該水瓶。

UIView *view = [[UIView alloc] init];
NSLog(@"創(chuàng)建之后的默認(rèn)值是:%ld",(unsigned long)view.retainCount); //創(chuàng)建之后的默認(rèn)值是:1
[view retain];
NSLog(@"通過一次retain操作之后:%ld",(unsigned long)view.retainCount); //通過一次retain操作之后:2
[view release];
NSLog(@"通過一次release操作之后:%ld",(unsigned long)view.retainCount); //通過一次release操作之后:1
上面的四種操作中除開`autorelease `方法外都比較好理解,關(guān)于`autorelease `可以點(diǎn)擊[黑幕背后的Autorelease](http://blog.sunnyxx.com/2014/10/15/behind-autorelease/)。同時(shí)《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法》書中有這樣解釋的:

在OC引用計(jì)數(shù)框架中,自動(dòng)釋放池是一項(xiàng)重要特性,調(diào)用release會(huì)立刻遞減對象的引用計(jì)數(shù)(而且很可能令系統(tǒng)回收此對象)然而有時(shí)候可以不調(diào)用它,改為調(diào)用autorelease,此方法會(huì)在稍后遞減計(jì)數(shù),通常是在下一次“事件循環(huán)“(even loop)時(shí)遞減,不過也可能執(zhí)行的更早。此特性很有用,尤其是在方法中返回對象時(shí)更應(yīng)該用它。

該書中還舉出了這樣的例子:

- (NSString *)stringValue {
  NSString *str = [[NSString alloc] initWithFormat:@"i am this: %@",self];
  return str;
}

此時(shí)返回的str對象計(jì)數(shù)值比期望值要+1,因?yàn)榉椒▋?nèi)部調(diào)用了一次alloc操作而又沒有與之對應(yīng)的釋放操作,計(jì)數(shù)器+1就意味著調(diào)用者要負(fù)責(zé)處理多出來的這一次保留操作。但是不能在- (NSString *)stringValue方法內(nèi)部釋放,否則還沒等方法返回,系統(tǒng)就把該對象回收了,這時(shí)候應(yīng)該使用autorelease,他能夠延長對象的生命周期,保證方法返回后該對象一定有效并且在合適的時(shí)機(jī)得以釋放。

【注意】:關(guān)于一個(gè)對象的retainCount大部分情況下是合理的,但是有些時(shí)候其數(shù)值是令人無法理解的。例如蘋果官方文檔對其做了下面的解釋:

蘋果官方對`retainCount`的解釋

文檔的大致內(nèi)容是:此方法在調(diào)試內(nèi)存管理問題上作用不大。 因?yàn)槿我獾目蚣軐ο罂赡芤迷搶ο?,同時(shí)自動(dòng)釋放池對對象有延遲釋放作用,因此無法通過調(diào)用此方法獲取到有用的信息。

  • 對象的銷毀

    • 對象何時(shí)被銷毀:當(dāng)對象的引用計(jì)數(shù)器值為0時(shí),它將被系統(tǒng)銷毀,其占用的內(nèi)存空間將得到釋放。
    • - (void)dealloc:當(dāng)對象被銷毀時(shí),系統(tǒng)會(huì)調(diào)用該方法,重寫該方法并在其中釋放相應(yīng)的資源如移除通知等(類似于臨終遺言),一旦重寫dealloc方法就必須在代碼塊最后調(diào)用[super dealloc]方法,調(diào)用[super dealloc]方法是為了讓super釋放相應(yīng)的資源,使得任何繼承來的對象都能夠得到釋放;另外我們不應(yīng)該直接調(diào)用對象的delloc方法。

    例如下面的代碼:

@implementation Person
   - (void)dealloc
   {
    NSLog(@"對象被銷毀了");
    [super dealloc];
   }
@end
 Person *p1 = [[Person alloc] init];
 NSLog(@"%lu",(unsigned long)p1.retainCount);
 [p1 release];

控制臺(tái)輸出信息

2017-01-28 18:11:29.431764 OC中對象內(nèi)存管理[20948:160747] 1
2017-01-28 18:11:29.432173 OC中對象內(nèi)存管理[20948:160747] 對象被銷毀了

內(nèi)存管理的范圍

有了上面關(guān)于Objc對象知識(shí)的鋪墊,我們可以很好的引入內(nèi)存管理這個(gè)概念。

  • 范圍:管理任何繼承自NSObject類型的對象的內(nèi)存。對于其他基本數(shù)據(jù)類型如:int、char、double、結(jié)構(gòu)體、枚舉類型的變量無效。

  • 根本原因:ObjC對象和其他的基本類型變量在內(nèi)存中存儲(chǔ)位置不同,對象所占的內(nèi)存由系統(tǒng)在堆區(qū)動(dòng)態(tài)分配需要程序員管理手動(dòng)釋放,而其他基本數(shù)據(jù)類型的變量(局部變量)一般分配在棧區(qū)由系統(tǒng)自動(dòng)釋放。

內(nèi)存管理的方式

  • Objective-C中為我們提供了兩種(曾經(jīng)是三種)管理內(nèi)存的方式:
    • Mannul Reference Counting (MRC)
      手動(dòng)內(nèi)存管理,指的是通過retain、release、autorelease等使用引用計(jì)數(shù)器操作的方式由程序員手動(dòng)管理內(nèi)存。本文中所有涉及到以上三個(gè)方法的代碼都是MRC的實(shí)踐。MRC最大的問題在于持有和釋放對象的時(shí)機(jī),不當(dāng)?shù)?code>retain和release極可能產(chǎn)生“野指針”和“內(nèi)存泄露”等內(nèi)存方面的問題(下文中有具體介紹)。

    • Automatic Reference Counting (ARC)
      自動(dòng)內(nèi)存管理,ARC作為WWDC2011和iOS5之后LLVM 3.0編譯器的一項(xiàng)新特性,極大的解放了iOS開發(fā)者的雙手(蘋果推薦使用)。在ARC的編譯環(huán)境下開發(fā)者再也不用寫任何含有retain、release、autorelease的代碼了,編譯器將自動(dòng)在合適的地方插入上述代碼實(shí)現(xiàn)內(nèi)存的管理。事實(shí)上現(xiàn)在絕大部分代碼都是使用的ARC管理內(nèi)存,只是作為初學(xué)者可能“日用而不知”,并沒有意識(shí)到其中深層次的關(guān)系,并且在ARC環(huán)境下編寫含有引用計(jì)數(shù)操作的代碼是無法編譯通過的。例如:

      ARC與引用計(jì)數(shù)操作

      ARC與 [supper delloc]

MRC和ARC的區(qū)別示意圖

關(guān)于更多MAC和ARC機(jī)制的內(nèi)容請參考以下博客:
王巍 (@onevcat):手把手教你ARC——iOS/Mac開發(fā)ARC入門和使用
HIT-Alibaba:Objective-C 中的內(nèi)存分配
Apple:Transitioning to ARC Release Notes

  • Gargage Collection (垃圾回收機(jī)制)
    Objective-C 2.0以后存在垃圾回收機(jī)制。垃圾回收機(jī)制監(jiān)視整個(gè)對象關(guān)系圖,查找那些在作用域內(nèi)已沒有任何指針指向的對象,并自動(dòng)釋放這些對象。
    另外在《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法》一書中對垃圾回收機(jī)制有這樣的描述:

從Mac OS X10.8開始,“垃圾收集器”(garbage collector)已經(jīng)正式廢棄了,以后Objective-C代碼編寫Mac OS X程序時(shí)不應(yīng)再使用它,而iOS則從未支持過垃圾收集。

由于關(guān)于Objective-C垃圾回收的資料本人收集的比較少,僅在《好學(xué)的Objective-C》一書中看到過相關(guān)介紹,而且該機(jī)制從未在iOS開發(fā)中使用到,所以筆者這里姑且認(rèn)為Objective-C中是存在過三種內(nèi)存管理的方式,只是沒法介紹關(guān)于它的更多內(nèi)容。有興趣的同學(xué)可以查閱一下該書。

內(nèi)存管理的原則

  • 只要對象還在被使用其占用的內(nèi)存空間就不應(yīng)該被回收;需要使用該對象,使該對象引用計(jì)數(shù)+1;使用完該對象,使該對象的引用計(jì)數(shù)-1。
  • 誰創(chuàng)建,誰release
  • 誰retain,誰release

具體來說當(dāng)使用alloc、newcopy(生成一個(gè)接受對象的副本)創(chuàng)建對象時(shí),其引用計(jì)數(shù)器值被置為1,當(dāng)不需要使用該對象時(shí)需要做一次release操作;當(dāng)使用retain操作持有一個(gè)對象時(shí)其引用計(jì)數(shù)器值+1,當(dāng)不需要使用該對象時(shí)需要做一次release操作;一次創(chuàng)建對應(yīng)著一次release,一次retain對應(yīng)著一次release,這樣對象才能“有始有終”。

內(nèi)存管理不當(dāng)導(dǎo)致的問題

  • 野指針
  • 定義的指針變量沒有初始化。
  • 指向的堆內(nèi)存空間已經(jīng)被釋放的指針。
Dog *yellowDog = [[Dog alloc] init];
[yellowDog release];
NSLog(@"%@", yellowDog);

上面的代碼在yellowDog 的引用計(jì)數(shù)器值為0時(shí)已經(jīng)將在堆區(qū)分配的 Dog 對象的內(nèi)存釋放掉了,再調(diào)用NSLog通過yellowDog指針訪問堆區(qū)的對象就很可能會(huì)出問題。

Person *p1 = [Person new];
[p1 release];
[p1 release];

如上的代碼,當(dāng)?shù)谝淮螆?zhí)行[p1 release]代碼時(shí),p1指向的對象的retainCount減為0,系統(tǒng)銷毀該對象且其在堆區(qū)的存儲(chǔ)空間會(huì)被回收,如果此時(shí)再次執(zhí)行[p1 release]代碼,嘗試給已經(jīng)被釋放的Pweson對象發(fā)送release消息,很可能會(huì)觸發(fā)運(yùn)行時(shí)錯(cuò)誤。具體來說程序運(yùn)行成功但是控制臺(tái)會(huì)輸出這樣的信息:

Person object 0x1002049e0 overreleased while already deallocating; break on objc_overrelease_during_dealloc_error to debug

《Effective Objective-C 2.0 編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法》一書是這樣解釋 “很可能”這個(gè)詞的:

之所以說“很可能”沒有說一定,是因?yàn)閷ο笤诙褏^(qū)所占的內(nèi)存在“解除分配”(deallocated)之后只是放回到“可用內(nèi)存池”,如果此時(shí)執(zhí)行NSLog時(shí)尚未覆蓋對象內(nèi)存,那么該對象依舊有效,這時(shí)程序不會(huì)奔潰。由此可見,因過早釋放對象而導(dǎo)致的bug很難調(diào)試。

當(dāng)我們開啟Xcode的僵尸對象檢測功能時(shí),程序運(yùn)行崩潰,在控制臺(tái)輸出如下信息:

*** -[Person release]: message sent to deallocated instance 0x100200640
//release 消息發(fā)送給了一個(gè)已經(jīng)釋放掉的對象

上面的情況在日常開發(fā)中常常體現(xiàn)為Thread:EXC_BAD_ACCESS(壞訪問錯(cuò)誤)
【壞訪問錯(cuò)誤】:即訪問了一塊壞內(nèi)存(不可用的已經(jīng)被回收的內(nèi)存)。這樣的錯(cuò)誤我們也稱為“野指針錯(cuò)誤”,意思是利用野指針操作了一塊不可用的內(nèi)存。
【僵尸對象】:所占用的內(nèi)存空間已經(jīng)被回收不可用的對象。僵尸對象不應(yīng)該再使用。
【解決方案】:為避免在不經(jīng)意間使用了無效對象,一般調(diào)完realease之后都會(huì)清空指針。這樣就能保證不會(huì)可能出現(xiàn)指向無效對象的指針。即在對象釋放完畢后將指向?qū)ο蟮闹羔樦脼?code>nil,給nil發(fā)消息不會(huì)產(chǎn)生任何反應(yīng)。
綜上所述:沒有置為nil卻指向了無效對象的指針就是野指針

所以正確的做法應(yīng)該是:
Dog * yellowDog = [[Dog alloc] init];
[yellowDog release];
yellowDog = nil //對象釋放后,將指向?qū)ο蟮闹羔樦脼閚il
  • 內(nèi)存泄漏
{   //代碼塊內(nèi)創(chuàng)建Dog對象
      Dog *husky = [[Dog alloc] init];
}

形如上面的代碼,當(dāng)我們在創(chuàng)建Dog對象時(shí)系統(tǒng)分別在棧區(qū)為husky變量分配內(nèi)存、在堆區(qū)為husky所指向的Dog對象分配內(nèi)存,由于變量husky的作用域在大括號(hào)內(nèi)屬于局部變量,當(dāng)代碼塊執(zhí)行完畢,棧中的husky變量就被釋放了,但是此時(shí)在代碼塊中并沒有對husky變量指向的堆區(qū)的對象存儲(chǔ)空間進(jìn)行釋放,所以我們說堆區(qū)中對應(yīng)的存儲(chǔ)空間就被泄露了。

總結(jié)為:基本的數(shù)據(jù)類型由于占用的存儲(chǔ)空間是固定的,一般存在棧區(qū)中。由于棧中主要存放的是局部變量,局部變量占用的內(nèi)存空間是其所在的代碼塊或者是函數(shù)結(jié)束的時(shí)候自動(dòng)回收,指向?qū)ο蟮闹羔樢矔?huì)被回收,這個(gè)過程不需要程序員管理。但是對象創(chuàng)建完成后是存放在堆區(qū)的,由于此時(shí)指向?qū)ο蟮闹羔樢呀?jīng)被回收,但是對象仍然存在內(nèi)存中,就會(huì)造成內(nèi)存泄漏(申請的空間已經(jīng)不再使用卻沒有被及時(shí)合理的釋放掉)。

文章最后

以上就是筆者對于Objective-C內(nèi)存管理基礎(chǔ)認(rèn)識(shí)的全部內(nèi)容,部分描述引自書籍和其它博客文中已經(jīng)做出了說明,但凡是本人認(rèn)為重要的概念均附上其它博客的鏈接用于擴(kuò)展相關(guān)知識(shí)。

另外:本文涉及到MRC的代碼需要在Xcode進(jìn)行如下設(shè)置才能編譯通過:在Build Settings中,找到"Objective-C Automatic Reference Counting"這個(gè)選項(xiàng),將它的值改為"NO"。

如果文中有任何紕漏或錯(cuò)誤歡迎在評論區(qū)留言指出,本人將在第一時(shí)間修改過來;喜歡我的文章,可以關(guān)注我以此促進(jìn)交流學(xué)習(xí); 如果覺得此文戳中了你的G點(diǎn)請隨手點(diǎn)贊;轉(zhuǎn)載請注明出處,謝謝支持。

下一篇:Objective-C 內(nèi)存管理深入

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.1 什么是自動(dòng)引用計(jì)數(shù) 概念:在 LLVM 編譯器中設(shè)置 ARC(Automaitc Reference Co...
    __silhouette閱讀 5,472評論 1 17
  • 說起內(nèi)存管理,看似老生常談,但是真正掌握內(nèi)存管理并不簡單。小伙伴們要加油了。 Objective-C的內(nèi)存管理機(jī)制...
    ARU閱讀 370評論 1 1
  • 29.理解引用計(jì)數(shù) Objective-C語言使用引用計(jì)數(shù)來管理內(nèi)存,也就是說,每個(gè)對象都有個(gè)可以遞增或遞減的計(jì)數(shù)...
    Code_Ninja閱讀 1,742評論 1 3
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,058評論 0 9
  • 內(nèi)存管理 簡述OC中內(nèi)存管理機(jī)制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,081評論 1 16

友情鏈接更多精彩內(nèi)容