第一章 ARC
使用ARC的條件:
引用計數的機制
用開關房間的燈來作比喻,需要照明的人數(即引用數),當引用數大于0開燈,當引用數等于0關燈
1.2.2 內存管理的思考方式
按照此思考方式,完全不用考慮引用計數
- 自己生成的對象,自己持有
- 非自己生成的對象,自己也能持有
非自己生成的對象,即用alloc/new/copy/mutableCopy以外取得的對象
方法中生成對象,并將其返回給調用方是怎么實現的?
-
不再需要自己持有對象時釋放
釋放了非自己持有的對象就會造成崩潰
image.png
生成、持有、釋放、廢棄
這些內存管理的有關方法,實際上不包括在語言中,而是包含在Cocoa框架中。Cocoa框架中的Foundation框架類庫的NSObject類擔負內存管理的職責。
1.2.3 GNUstep alloc/retain/release/dealloc 的實現
參考資料
alloc
alloc -- allocWithZone -- NSAllocateObject -- NSZoneMalloc
NSZone:為了防止內存碎片化而引入的結構
retain
只是是retained變量+1
release
當retained變量大于0時候-1,當等于0的時候調用dealloc實例方法
1.2.4 蘋果alloc/retain/release/dealloc 的實現
+alloc
+allocWithZone
class_createInstance
calloc
__CFDoExternRefOperation函數
蘋果就是采用散列表(引用計數表)來管理引用計數。
- 對比GNUstep和蘋果兩種管理引用計數的方式
1.2.5 autorelease
1.2.6 GNUstep的autorelease實現
IMP 緩存
在GNUstep中,實際NSAutoreleasePool的addObject使用的是鏈表
1.2.7 蘋果的autorelease實現
1.3 ARC規則
1.3.1
同一個程序中可以以文件為單位設置ARC有效/無效
1.3.3 所有權修飾符
第二章 Blocks
第三章 GCD
3.1 什么是GCD
使用GCD一般就兩個步驟:
獲取隊列
調用方法,將任務添加進隊列中
3.2 什么是多線程
線程:
多線程:
一個CPU反復在多個線程間切換,就好像多個線程可以并列執行一樣,而在具有多個CPU核的情況下,就可以真的提供多個CPU核并行執行多個線程了
多線程問題:
數據競爭、死鎖、消耗大量內存
3.3 GCD的API
Dispatch Queue
:執行處理的等待隊列,分兩種
Serial DispatchQueue
:串行隊列 等待現在執行中處理結束
Concurrent Dispatch Queue
:并行隊列 不等待現在執行中處理結束
Dispatch Queue
和線程的關系:
主線程中的隊列是Main Dispatch Queue
,因為主線程只有一個,所以Main Dispatch Queue
自然就是 Serial Dispatch Queue
(我的理解:隊列是用來派發任務的,而線程是用來處理任務的)
一旦生成Serial DispatchQueue
并追加處理,系統對于一個Serial DispatchQueue
就只生成并使用一個線程。如果生成2000個Serial DispatchQueue
,那么就生成2000個線程。所以Serial DispatchQueue
的生成個數應當僅限所必須的數量。如果過多使用多線程,就會大量消耗內存,引起大量的上下文切換,大幅度降低系統的響應性能。
XNU內核決定Concurrent Dispatch Queue
應該使用的線程數量
得到Dispatch Queue
的方法
- 創建
/*
參數一:線程名,一般那采用 逆序域名
參數二:NULL代表生成Serial DispatchQueue,生成Concurrent Dispatch Queue需指定為DISPATCH_QUEUE_CONCURRENT
*/
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.example.gcd.myConcurrentDispatchQueue",DISPATCH_QUEUE_CONCURRENT);
注意:對于最低sdk版本>=iOS6.0來說,GCD對象已經納入了ARC的管理范圍,我們就不需要再手工調用 dispatch_release
了
- 獲取系統標準提供的
Dispatch Queue
Main Dispatch Queue
屬于Serial DispatchQueue
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
Global Dispatch Queue
所有的應用程序都能使用的Concurrent Dispatch Queue
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
Global Dispatch Queue
的4個執行優先級:
高優先級:DISPATCH_QUEUE_PRIORITY_HIGH
默認優先級:DISPATCH_QUEUE_PRIORITY_DEFAULT
低優先級:DISPATCH_QUEUE_PRIORITY_LOW
后臺優先級:DISPATCH_QUEUE_PRIORITY_BACKGROUND
3.2.4 變更隊列的優先級和執行層次dispatch_set_target_queue
變更隊列優先級
dispatch_queue_t mySerialDispatchQueue = = dispatch_queue_create("com.example.gcd.mySerialDispatchQueue",NULL);
dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);
// 變更mySerialDispatchQueue的優先級,使之和globalDispatchQueueBackground相同
dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);
變更執行層次
如果在多個Serial Dispatch Queue
中用dispatch_set_target_queue
函數指定目標為某一個Serial Dispatch Queue
,那么原先應該并行執行的多個Serial Dispatch Queue
,在目標Serial Dispatch Queue
上只能同時執行一個處理。
3.2.5 指定時間追加到Dispatch Queue
,dispatch_after
/*
dispatch_time() 用于計算相對時間
第一個參數:指定開始時間
第二個參數:NSEC_PER_SEC 秒 ,NSEC_PER_MSEC 毫秒
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,3ull * NSEC_PER_SEC);
dispatch_after(time,dispatch_get_main_queue(),^{
NSLog(@"waited at least three seconds.");
})
// 用于計算絕對時間
dispatch_walltime
注意:dispatch_after
并不是在指定時間后執行處理,而是在指定時間追加處理到Dispatch Queue
3.2.6 Dispatch Group
在追加到Dispatch Queue
中的多個處理全部結束后,想執行結束處理
dispatch_quque_t queue
dispatch_group_notify(group,dispatch_get_main_queue(),^{
NSLog()@"done";
});
// 相比dispatch_group_notify多了一個超時時間
dispatch_group_wait
3.2.7 dispatch_barrier_async
3.2.8 dispatch_sync
串行隊列中(包括主隊列),同步嵌套會造成死鎖
dispatch_barrier_sync
3.2.9 dispatch_apply
代替for循環