1. 程式人生 > >iOS開發中的ARC記憶體管理機制(1)——基礎概念

iOS開發中的ARC記憶體管理機制(1)——基礎概念

由於移動裝置的記憶體資源一般比較少,所以垃圾回收機制的操作會對裝置的效能造成比較明顯的影響,有可能在執行垃圾回收的時候讓移動裝置出現卡頓,這對於使用者來說是很難受的事。

由此蘋果公司提出了ARC方案。

0x01 自動引用計數

自動引用計數(Automatic Reference Counting,ARC),ARC會追蹤程式中的物件並決定哪一個仍會使用到而哪一個不會再用到,在編譯期,ARC就已經用更底層的C介面實現了retain/release/autorelease,效能非常好;

不同於垃圾回收器(GC)通過返回的程式碼來定期檢查物件,佔用了系統資源。

如果啟用了ARC,只管像平常一樣按需分配並使用物件,編譯器會幫我們插入retain/release語句,

相當於編譯器替我們完成了記憶體管理的工作。

0x02 編寫ARC程式碼所需的條件

1、能夠確定哪些物件需要進行記憶體管理

該條件要求物件的最上層集合應該知道如何去管理它的子物件。如果物件是不可保留的,則無法使用ARC特性:

NSString **myString;
myString = malloc(10 * sizeof(NSString *));

//C風格陣列是不可保留的物件,不能使用ARC特性

2、能夠表明如何去管理物件

該條件要求程式設計師能夠對某個物件的引用計數器值進行+1 / -1操作,NSObject類的子類都能進行記憶體管理;

3、有可行的辦法傳遞物件的所有權

該條件要求程式能夠在呼叫者和接收者之間傳遞物件的所有權;

4、編譯環境及使用環境:

  • Xcode 4.2以上版本;
  • Apple LLVM 3.0以上版本的編譯器;
  • MAC OS X 10.7以上版本的系統;
  • 包括歸零弱引用(Zeroing Weak Reference),需要iOS 5.0或MAC OS X 10.7以上版本的支援。

0x03 ARC的使用規則

1、程式碼中不能使用retain、release、retain和autorelease方法;

2、不過載dealloc方法(如果是釋放物件記憶體以外的操作是可以過載該函式的,但是不能直接呼叫[super dealloc]);

3、不能使用NSAllocateObject和NSDeallocateObject;

4、不能在C結構體中使用物件指標;

5、id與void *間的如果發生所有權傳遞時需要用特定的方法(__bridge關鍵字);

6、不能使用NSAutoReleasePool,而需要使用@autoreleasepool塊;

7、不能使用“new”開始的屬性名稱 (如果使用會有下面的編譯錯誤”Property’s synthesized getter follows Cocoa naming convention for returning ‘owned’ objects”);

8、屬性不能只有一個read-only而沒有記憶體管理屬性,必須指定由誰來管理記憶體。

0x04 使用ARC的優點

使用ARC後寫Objective-C程式碼就不需要操心複雜的記憶體管理和擔心記憶體洩露了,把記憶體管理工作交給編譯器,也有利於提高程式碼效率。最直觀的一點就是程式碼總量變少,更容易閱讀:

使用ARC前:

@interface NonARCObject : NSObject {    
    NSString *name;    
}    
-(id)initWithName:(NSString *)name;    
@end    
   
@implementation NonARCObject    
-(id)initWithName:(NSString *)newName {    
    self = [super init];    
    if (self) {    
        name = [newName retain];    
    }    
    return self;    
}    
   
-(void)dealloc {    
    [name release];    
    [Super dealloc];    
}    
@end    

使用ARC後:

@interface ARCObject : NSObject {    
    NSString *name;    
}    
-(id)initWithName:(NSString *)name;    
@end    
   
@implementation ARCObject    
-(id)initWithName:(NSString *)newName {    
    self = [super init];    
    if (self) {    
        name = newName;    
    }    
    return self;    
}    
@end