NSObject
的全部對象,這些對象都是引用類型。int
, float
等數據類型,這些對象都是值類型。棧的效率會相對較高。Apple提供了兩種內存管理方式:html
alloc
, new
, copy
或者mutableCopy
等方法命名的方法建立的對象,像stringWithFormat:
等方法建立的對象並不能被持有retain
來獲取對象的擁有關係:retain
使用場景有兩個: 1)在訪問器的方法實現或者是init
方法中,獲取想要的對象,並將其做爲屬性值 2)避免其餘操做對該對象的形成的影響release
或者autorelease
的消息給該對象release
和autorelease
發送release
消息的話,會立刻將對象釋放掉。若是想要延遲釋放對象的話,可使用autorelease
.git
經過引用返回的對象並不能被持有。github
dealloc
來捨棄對象的持有這裏須要注意的一點是不能直接調用其餘對象的dealloc
方法app
init
或者dealloc
方法中使用訪問器方法蘋果在官方文檔中提到,不要在初始化或者是釋放方法中使用Accessor Methods(這多是在MRC階段的,蘋果的內存管理文檔是比較久以前,不過這是我的理解,有待驗證)。因此在初始化的方法中,應該這樣:ide
- (instancetype)init {
self = [super init];
if (self) {
_count = [[NSNumber alloc] initWithInteger: 0];
}
return self;
}
複製代碼
對於通常的OC對象,只須要使用ARC來進行計數實現內存管理便可。對於底層的Core Foundation來講,則須要調用CFRetain()
和CFRelease()
這兩個方法來增減引用計數。工具
OC對象和Core Foundation對象的轉換經過bridge
關鍵字進行轉換。oop
__bridge
: 只進行類型轉換,不修改引用計數__bridge_retained
: 類型轉換後引用計數加1__bridge_transfer
: 類型轉換後將對象的引用計數交給ARC管理weak引用是一種non-owning
的關係,因此並不會retain對象。ui
聲明爲weak
的變量能夠防止循環引用形成的內存問題,由於若是對象沒有了強引用的話,就會被置爲nil。這一點須要跟unsafe_unretained
區分開來。unsafe_unretained
的對象若是沒有了強引用,並不會被置爲nil。若是對象被回收或者銷燬的話,該指針就會變爲野指針。spa
retain一個對象會建立該對象的強引用。命令行
循環引用的一種解決方式是使用weak引用。如圖中所示,Cocoa有一個約定,就是父對象對其子對象是強引用,子對象則是對父對象弱引用。用上面的例子來講的話,就是Page對象強引用了Paragraph, Paragraph弱引用了Page.
發送消息給已經釋放的對象的話,程序會crash,這點須要跟發送消息給nil
進行區分。OC是容許發送消息給nil
的。
如Array, Dictionary和Set等集合對象,retain其object,在移除對象或者集合對象被釋放的時候纔會將該object捨棄。
野指針致使的錯誤一般在Xcode中表現爲:Thread 1: EXC_BAD_ACCESS(code=EXC_I386_GPFIT)
錯誤。緣由是訪問了一塊已經釋放或者不屬於你的內存。
alloc
, copy
, init
, mutableCopy
和new
打頭的方法[NSString stringWithFormat:]
這樣的方法內存泄露有兩種類型:
其中第一種可使用Leak工具來檢測,第二種使用Allocations來檢測
Block一開始是釋放在棧中,可是在運行時會調用Block_copy
方法將block對象複製到堆中,而且將引用計數加1,返回新的block指針(若是block對象已經存在於堆中的話,則引用計數加1)。而Block_release
方法則是將引用計數減一,或者在計數爲0時將對象釋放摧毀。
#0x08 Autorelease Pool Block
@autoreleasepool {
// Code
}
複製代碼
通常在下面三種狀況下須要使用autoreleasepool
:
autoreleasepool
block, 不然會形成內存泄漏alloc
和release
配套使用