1、關於Alloc Retain Release 等web
Aciton for Object-C Object |
Objective-C Method |
Create and have ownership of it | alloc/new/copy/mutableCopy group |
Take ownership of it | retain |
Relinquish it | release |
Dispose of it | dealloc |
alloc:建立一個對象,並擁有這個對象的使用權利。The implementation of alloc in NSObject:數組
關於NSZone: 是蘋果對內存分配和釋放的優化方式。NSZone不是一個對象;它是一個難懂的C結構,它被用於紀錄關於內存處理(管理)一系列對象的信息。 你幾乎不須要擔心你本身的應用(applications)是怎樣管理你本身的空間(zones)的 ;Cocoa透明地管理它。默認的NSZone在程序啓動和全部對象被分配時建立。 若是你大量分配數百個小對象,事實上你會發現你花費精力來爲他們分配內存是有意義的。由於這種標準的(默認的)空間會被一直使用,它會變得斑駁起來;釋放對象的過程會給整個內存留下使人尷尬的空隙。標準空間的分配器(allocator)也知道知道這一點,因此它嘗試着優先去使用被用戶釋放的內存,去填補這些空隙,可是這種方式只有在空間(zone) 變得很大時纔有明顯效果。
使用NSZone + (id) alloc {return [self allocWithZone: NSDefaultMallocZone()]; } + (id) allocWithZone: (NSZone*)z {return NSAllocateObject (self, 0, z); } struct obj_layout { NSUInteger retained; }; inline id NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) { int size = /* needed size to store the object */ id new = NSZoneMalloc(zone, size); // 調用NSZoneMalloc 開闢一塊內存空間,返回內存地址 memset(new, 0, size); new = (id)&((struct obj_layout *)new)[1]; } 去掉NSZone: struct obj_layout { NSUInteger retained; }; + (id) alloc { int size = sizeof(struct obj_layout) + size_of_the_object; struct obj_layout *p = (struct obj_layout *)calloc(1, size); return (id)(p + 1); }
retian:釋放舊的對象,將舊對象的值賦予輸入對象,再提升輸入對象的索引計數爲 1。指針的拷貝app
- (id) retain { NSIncrementExtraRefCount(self); return self; } inline void NSIncrementExtraRefCount(id anObject) { if (((struct obj_layout *)anObject)[-1].retained == UINT_MAX - 1) [NSException raise: NSInternalInconsistencyExceptionformat: @"NSIncrementExtraRefCount() asked to increment too far"]; ((struct obj_layout *)anObject)[-1].retained++; }
release:通知內存釋放這個對象,只有release纔會真正釋放內存。函數
- (void) release {if (NSDecrementExtraRefCountWasZero(self)) [self dealloc]; } BOOLNSDecrementExtraRefCountWasZero(id anObject) {if (((struct obj_layout *)anObject)[-1].retained == 0) { return YES; } else { ((struct obj_layout *)anObject)[-1].retained--; return NO; } }
nil:是把一個對象的指針置爲空,切斷了指針與內存中對象的聯繫;優化
release與nil 使用的前後順序:ui
若是沒有release就直接nil,那麼雖然不會出錯,卻等於本身製造內存泄漏了,由於nil以後release就已經不起做用了。相反,若是在使用接口對象時只僅僅release沒有設置self.objc =nil,那麼程序可能也不會報錯,但卻會十分不穩定、不健壯,很容易發生崩潰現象。由於一個接口對象在release以後,給它所分配等內存就已經被釋放了,若是釋放以後系統再用到這個對象,那麼程序就會crash。若是釋放以後把它的指針置爲空,則即使後面的程序用到該對象,也不會崩潰。spa
dealloc:衆所周知,dealloc是非ARC狀況下,調用dealloc是釋放內存的。ARC環境下,也沒有把dealloc函數禁掉,仍是可使用的,只不過不用調用[super dealloc]了。例如:頁面中調用webview。.net
若是在WebView載入完成以前關閉畫面的話,畫面關閉後,ViewController也釋放了。但因爲WebView正在載入頁面,而不會立刻被釋放,等到頁面載入完畢後,回調delegate(ViewController)中的方法,因爲此時ViewController已經被釋放,因此會出錯。指針
解決辦法是在dealloc中把WebView的delegate釋放。code
-(void)dealloc {
self.webView.delegate = nil;
}
附錄:
一、關於self的用法 找到一篇博客寫的不錯(http://blog.csdn.net/zhibudefeng/article/details/7714808)
主要是關於OC裏面的getter、setter有關。self.object 與 myClass -> myObject來訪問, 這樣是直接訪問對象自己
二、關於聲明成IBOutlet屬性:
在MRC中,IBOutlet自己就是retain 任何一個被聲明爲IBOutlet而且在Interface Builder裏被鏈接到一個UI組件的成員變量,會被額外retain一次。因此使用了IBOutlet變量,必定要在dealloc/viewDidUnload裏釋放這個變量
在ARC中,咱們使用IBOutlet屬性都聲明爲weak。經過加載xib獲得的用戶界面,在其從xib文件加載時,就已是view hierarchy的一部分了,而view hierarchy中的指向都是strong的。所以outlet所指向的UI對象不該當再被hold一次了
2、NSAutoreleasePool 的使用:
Apple's implementtation of autorelease in runtime/objc-arr.mm
class AutoreleasePoolPage {static inline void *push() {/* It corresponds to creation and ownership of an NSAutoreleasePool object */ } static inline void pop(void *token) {/* It corresponds to disposal of an NSAutoreleasePool object */ releaseAll(); } static inline id autorelease(id obj) {/* It corresponds to NSAutoreleasePool class method addObject. */ AutoreleasePoolPage *autoreleasePoolPage = /* getting active AutoreleasePoolPage object */ autoreleasePoolPage->add(obj); } id *add(id obj) {/* add the obj to an internal array; */ } void releaseAll() {/* calls release for all the objects in the internal array */ } }; void *objc_autoreleasePoolPush(void) {return AutoreleasePoolPage::push(); } void objc_autoreleasePoolPop(void *ctxt) {AutoreleasePoolPage::pop(ctxt); } id objc_autorelease(id obj) {return AutoreleasePoolPage::autorelease(obj); }
例如:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // equivalent to objc_autoreleasePoolPush() id obj = [[NSObject alloc] init]; [obj autorelease]; // equivalent to objc_autorelease(obj) [pool drain]; // equivalent to objc_autoreleasePoolPop(pool)
當drain 被調用的時候,會調用dealloc函數來釋放pool的數組,在以前會先釋放pool數組裏面的全部object
-(void) drain { [self dealloc]; } -(void) dealloc { [self emptyPool]; [array release]; } -(void) emptyPool { for(id objc in array) { [objc release]; } }
在ARC與非ARC中,autoreleasepool的實現方式:
離開@autoreleasepool 的塊,全部建立的對象都會自動釋放