標籤:
記憶體管理作為iOS中非常重要的部分,每一個iOS開發人員都應該深入瞭解iOS記憶體管理,最近在學習iOS中整理出了一些知識點,先從MRC開始說起。
1.當一個對象在建立之後它的引用計數器為1,當調用這個對象的alloc、retain、new、copy方法之後引用計數器自動在原來的基礎上加1(ObjC中調用一個對象的方法就是給這個對象發送一個訊息),當調用這個對象的release方法之後它的引用計數器減1,如果一個對象的引用計數器為0,則系統會自動調用這個對象的dealloc方法來銷毀這個對象。
[email protected]的參數可以分為三類,也就是說最多可以有三個參數,參數的含義如下表:
參數類型 |
參數名 |
參數含義 |
原子性 |
atomic |
對屬性加鎖,安全執行緒,預設屬性 |
nonatomic |
不加鎖,非安全執行緒 |
讀寫屬性 |
readonly |
產生getter和setter方法,預設屬性 |
readwrite |
只產生getter方法 |
set方法處理 |
assign |
直接賦值,預設值 |
retain |
先release原來的值,再retain新值 |
copy |
先release原來的值,再copy新值 |
各種屬性對應的setter方法內容如下:
assign, 通常用於基礎資料型別 (Elementary Data Type),如:int,float
-(void)setA:(int)a{ _a=a;}
retain,通常用於非字串對象
-(void)setA:(A *)a{ if(_a!=a){ [_a release]; _a=[a retain]; }}
copy,通常用於字串對象,block,NSArray,NSDictionary
-(void)setA:(NSString *)a{ if(_a!=a){ [_a release]; _a=[a copy]; }}
3. 當使用手動引用計數的時候,Fundation架構中的一些方法可能會增加對象的引用計數,比如NSMutableArray中的addObject或者UIView中的addSubview,有一些方法將會減少對象的引用計數比如上面兩個介面對應的removeObjectAtIndex和removeFromSuperview。
4.再建立對象的時候推薦使用[[className alloc]init]而不是[className new],因為如果使用[className new],內部是調用的init方法初始化,我們就沒法調用initWithFrame之類的方法。
5.alloc:對象分配後引用計數為1,retain:對象的引用計數+1,copy:開闢新的記憶體存放新對象,引用計數為1,原對象引用計數不變。
6.給對象發送release訊息並不一定會銷毀這個對象,而是將對象的引用計數-1,如果對象的引用計數為0的話,對象就會被銷毀。然後系統會發送dealloc訊息給這個對象釋放它的記憶體。
7.對使用了retain、copy、mutableCopy、alloc、new方法的任何對象,以及具有retain和copy特性的屬性進行釋放,需要覆蓋dealloc方法,使得在對象被釋放的時候能夠釋放這些執行個體變數。
8.NSAutoreleasePool內部包含一個數組(NSMutableArray),用來儲存聲明為autorelease的所有對象。如果一個對象聲明為autorelease,系統所做的工作就是把這個對象加入到這個數組中去。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此對象加入autorelease pool中
NSAutoreleasePool自身在銷毀的時候,會遍曆一遍這個數組,release數組中的每個成員。如果此時數組中成員的retain count為1,那麼release之後,retain count為0,對象正式被銷毀。如果此時數組中成員的retain count大於1,那麼release之後,retain count大於0,此對象依然沒有被銷毀,記憶體泄露。如果再方法中不需要再使用這個對象,但是需要將其返回,可以向這個對象發送autorelease訊息將其放入到自動釋放池用以標記這個對象延遲釋放,autorelease並不會影響到對象的引用計數。
ClassA *Func1(){ ClassA *obj = [[[ClassA alloc]init]autorelease]; return obj;}
當引用程式終止的時候,記憶體中所有的對象都會被釋放,不論是否放入到自動釋放池中。如果對對象比較大的話不建議放入到自動釋放池中,因為自動釋放池延遲釋放會導致程式佔用記憶體較多。在iOS程式中會建立許多的自動釋放池,這些自動釋放池都是以棧(先進後出)的形式進行管理的,比如有兩個嵌套的自動釋放池:
@autoreleasepool { // 對象的釋放交給 自動釋放池去管理 不用再寫[person release] Person *person = [[[Person alloc] init] autorelease]; // 再建立一個自動釋放池2 @autoreleasepool { Person *person2 = [[[Person alloc] init] autorelease]; } Person *person3 = [[[Person alloc] init] autorelease]; }
釋放的順序就是person2->person->person3,先釋放內層的,再釋放外層的,同一層的從上到下釋放。
自從ARC出來之後,iOS開發記憶體管理便方便很多,總結要點如下:
1.__strong:表示引用為強引用。對應在定義property時的"strong"。所有對象只有當沒有任何一個強引用指向時,才會被釋放。如果屬性前面不加修飾符,預設的引用方式就是強引用,當需要釋放強引用指向的對象時,需要將強引用置nil。
2.__weak:表示為弱引用,弱引用不會影響到對象的釋放,就算有一百個弱引用指向某個對象,對象依然會被釋放(當沒有任何一個強引用指向該對象的時候),但是當對象被釋放之後,所有志向該對象的弱引用將會被置為nil。弱引用可以防止循環參考,比如delegate就是使用的弱引用。
3.__autoreleasing:表示在autorelease pool中自動釋放對象的引用,和MRC時代autorelease的用法相同。定義property時不能使用這個修飾符,任何一個對象的property都不應該是autorelease型的。以下兩行代碼的意義是相同的。
NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRCNSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC
4.聲明IBOutlet時一般應當使用weak,除了對StoryBoard這樣nib中間的頂層對象要用strong
5.weak相當於老版本的assign,strong相當於retain,copy的作用和原來一樣
6.不能直接調用dealloc方法,不能調用retain,release,autorelease,retainCount方法,包括@selector(retain)的方式也不行
7.可以用dealloc方法來管理一些資源,但不能用來釋放執行個體變數,也不能在dealloc方法裡面去掉[super dealloc]方法,在ARC下父類的dealloc同樣由編譯器來自動完成
IOS記憶體管理學習筆記