對象操做 | Objective-C方法 |
---|---|
生成並持有對象 | alloc/new/copy/mutableCopy等 |
持有對象 | retain |
釋放對象 | release |
廢棄對象 | dealloc |
Cocoa
框架中 Foundation
框架類庫的 NSObject
類擔負內存管理的職責。編程
使用如下名稱開頭的方法名意味着本身生成的對象只有本身持有:數組
alloc
new
copy
mutableCopy
使用 NSObject
類的 alloc
類方法就能本身生成並持有對象。另外,使用 new
類方法也能生成並持有對象。[NSObject new]
與 [[NSObject alloc] init]
是徹底一致的bash
用上述方法以外的方法取得的對象即用 alloc/new/copy/mutableCopy
之外的方法取得的對象,由於非本身生成並持有,因此本身不是該對象的持有者。例如 NSArray
類的 array
類方法。經過 retain
方法,非本身生成的對象成爲了本身所持有的。多線程
本身持有的對象,一旦再也不須要,持有者有義務釋放該對象,釋放使用的是 release
方法。 用 alloc/new/copy/mutableCopy
方法生成並持有的對象,或者用 retain
方法持有的對象,一旦再也不須要,務必要用 release
方法進行釋放併發
autorelease
提供這樣的功能,使對象再超出指定的生存範圍時可以自動並正確地釋放(調用release方法) app
對於用 alloc/new/copy/mutableCopy
方法生成並持有的對象,或者用 retain
方法持有的對象,因爲持有者是本身,因此在不須要該對象時須要將其釋放。而由此之外所獲得的對象絕對不能釋放。假若在應用程序中釋放了非本身所持有的對象就會形成崩潰。框架
Objective-C
的對象中存有引用技術這一整數值。alloc
或是 retain
方法後,引用計數值加 1.release
後,引用技術減 1.dealloc
方法廢棄對象。蘋果對引用計數大概是採用 散列表(引用計數表)來管理引用計數異步
GNUstep
將引用計數保存在對象佔用內存塊頭部的變量中,而蘋果則是保存在引用計數表的記錄中。async
經過內存塊頭部管理引用計數的好處:函數
經過引用計數表管理引用計數的好處:
在利用工具檢測內存泄露時,引用計數表的各記錄也有助於檢測各對象的持有者是否存在。
autorelease
autorelease
就是自動釋放,這看上去很像 ARC ,實際上更相似於 C 語言中自動變量(局部)變量的特性。 C 語言的自動變量特性:程序執行時,若某自動變量超出其做用域,該自動變量將被自動廢棄。 與 C 語言的自動變量不一樣的是,編程人員能夠設定變量的做用域。 autorelease
的具體使用方法以下:
NSAutoreleasePool
對象autorelease
實例方法NSAutoreleasePool
對象NSAutoreleasePool
對象的生存週期至關於 C 語言變量的做用域。對於全部調用過 autorelease
實例方法的對象,在廢棄NSAutoreleasePool
對象時,都將調用 release
實例方法。 在大量產生 autorelease
對象時,須要在適當的地方生成、持有或廢棄 NSAutoreleasePool
對象。 調用 NSObject
類的 autorelease
實例方法,該對象將被追加到正在使用的 NSAutoreleasePool
對象中的數組裏。即 本質就是調用 NSAutoreleasePool
對象的 addObject
類方法。
循環引用容易發生內存泄露,所謂內存泄露就是應當廢棄的對象在超出其生存週期後繼續存在。使用__weak
修飾符可避免循環引用,__weak
修飾符與__strong
修飾符 相反,提供弱引用。弱引用不能持有對象實例,由於__weak
修飾符的變量不吃又對象,因此在超出其變量做用域時,對象即被釋放。 __weak
修飾符還有另外一優勢:在持有對象的弱引用時,若該對象被被廢棄,則此弱引用將自動失效且處於 nil 被賦值的狀態。
在 ARC 有效的狀況下編譯源代碼需遵照以下規則:
retain/release/retainCount/autorelease
NSAllocateObject / NSDeallocateObject
dealloc
@autoreleasepoll
塊替代 NSAutoreleasePool
id
和 void *
, 經過 (__bridge void *)
或 (__bridge id)
進行橋接__weak
修飾符weak 表與引用計數表相同,做爲散列表被實現。若是使用 weak 表,將廢棄對象的變量的地址做爲鍵值進行檢索,就能高速地獲取對應的附有 __weak 修飾符的變量的地址。另外,因爲一個對象可同時賦值給多個附有 __weak 修飾符的變量中,因此對於一個鍵值,可註冊多個變量的地址。
若是附有 __weak 修飾符的變量所引用的對象被廢棄,則將 nil 賦值給該變量的步驟:
若是大量使用附有 __weak 修飾符的變量,會消耗相應的 CPU 資源,良策是隻在須要避免循環引用時使用 __weak 修飾符。
Blocks 是 C語言的擴充功能,用一句話表示:帶有自動變量(局部變量)的匿名函數。 Block 語法: ^ 返回值類型 參數列表 表達式
使用附有 __block
說明符修飾的自動變量可在 Block 中賦值,該變量成爲 __block
變量
在Block中,截獲自動變量的方法並無實現對C語言數組的截獲,這時使用指針能夠解決問題。
Block 本質是一個 OC 對象,它內部也有一個 isa 指針。是封裝了函數調用和函數調用環境的 OC 對象。
iOS 類的本質即 class_t
結構體:
struct class_t {
struct class_t *isa;
struct class_t *superclass;
Cache cache;
IMP *vtable;
uintptr_t data_NEVER_USE;
}
複製代碼
該實例名稱持有聲明的成員變量、方法的名稱、方法的實現(即函數指針)、屬性以及父類的指針。 Block 即爲 Objective-C 的對象。
類 | 設置對象的存儲域 | 備註 |
---|---|---|
_NSConcreteStackBlock | 棧 | 捕獲局部變量 |
_NSConcreteGlobalBlock | 程序的數據區域(.data 區) | 不捕獲自動變量 |
_NSConcreteMallocBlock | 堆 | 捕獲成員變量 |
Grand Central Dispatch (GCD) 是異步執行任務的技術之一,通常將應用程序中記述的線程管理用的代碼在系統級中實現,開發者只須要定義想執行的任務並追加到適當的 Dispatch Queue 中,GCD 就能生成必要的線程並計劃執行任務。
多線程編程可能會出現的問題:
Dispatch Queue 按照追加的順序(先進先出 FIFO)執行處理,另在執行處理時存在兩種 Dispatch Queue :一種是等待如今執行中處理的 Serial Dispatch Queue,另外一種是不等待如今執行中處理的 Concurrent Dispatch Queue。
可以使用 dispatch_set_target_queue
API 設置 Dispatch Queue 的優先級,同時也可使多個本應並行執行的多個 Serial Dispatch Queue,在目標 Serial Dispatch Queue 上串行執行。
dispatch_after
函數並不許時 由於 Main Dispatch Queue 在主線程的 Runloop 中執行,因此在好比每隔 1/60 秒自行的 Runloop 中,Block 最快3秒後自行,最慢在3秒 + 1/60 秒後執行,而且在 Main Dispatch Queue 有大量處理追加或主線程的處理自己有延遲時,這個時間會更長。
Dispatch Group
在追加到 Dispatch Queue 中的多個處理所有結束後想執行結束處理可以使用 Dispatch Group 實現。
dispatch_sync
如同簡易版的 dispatch_group_wait 函數,會在指定隊列中同步執行任務,在任務執行結束以前不會返回。若是在主線程同步執行 Block 就會出現死鎖。
dispatch_apply
函數可進行快速遍歷。因爲 dispatch_apply
函數與 dispatch_sync
函數相同,會等待處理執行結束,所以推薦在 dispatch_async
函數中非同步地執行 dispatch_apply
函數。
dispatch_suspend
函數可暫時掛起指定的 Dispatch Queue。 dispatch_resume
函數可恢復指定的 Dispatch Queue。
dispatch_semaphore
函數可對操做進行更細粒度的排他控制。 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
dispatch_semaphore_wait
函數等待 Dispatch Semaphore 的計數值達到大於或等於1. 該處理結束是使用 dispatch_semaphore_signal
函數將 Dispatch Semaphore 的計數值加1.
dispatch_once
函數是保證再應用程序執行中只執行一次指定處理的 API。
dispatch_IO
函數可多線程併發處理大文件,以提升文件讀取速度。
Block 並非直接加入 FIFO 隊列中,而是先加入 Dispatch Continuation 這一 dispatch_continuation_t
類型結構體中,而後再加入 FIFO 隊列。用於記憶 Block 所屬的 Dispatch Group 喝其餘一些信息,一般叫上下文。
。。。