iOS 學習日誌(3)--關於Automatic Reference Counting

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 的塊,全部建立的對象都會自動釋放

相關文章
相關標籤/搜索