第一章 ARC
使用ARC的條件:
引用計(jì)數(shù)的機(jī)制
用開(kāi)關(guān)房間的燈來(lái)作比喻霍骄,需要照明的人數(shù)(即引用數(shù)),當(dāng)引用數(shù)大于0開(kāi)燈鱼喉,當(dāng)引用數(shù)等于0關(guān)燈
1.2.2 內(nèi)存管理的思考方式
按照此思考方式奋单,完全不用考慮引用計(jì)數(shù)
- 自己生成的對(duì)象砚作,自己持有
- 非自己生成的對(duì)象蛤袒,自己也能持有
非自己生成的對(duì)象乘粒,即用alloc/new/copy/mutableCopy以外取得的對(duì)象
方法中生成對(duì)象,并將其返回給調(diào)用方是怎么實(shí)現(xiàn)的挺邀?
-
不再需要自己持有對(duì)象時(shí)釋放
釋放了非自己持有的對(duì)象就會(huì)造成崩潰
image.png
生成揉忘、持有、釋放悠夯、廢棄
這些內(nèi)存管理的有關(guān)方法癌淮,實(shí)際上不包括在語(yǔ)言中,而是包含在Cocoa框架中沦补。Cocoa框架中的Foundation框架類(lèi)庫(kù)的NSObject類(lèi)擔(dān)負(fù)內(nèi)存管理的職責(zé)乳蓄。
1.2.3 GNUstep alloc/retain/release/dealloc 的實(shí)現(xiàn)
參考資料
alloc
alloc -- allocWithZone -- NSAllocateObject -- NSZoneMalloc
NSZone:為了防止內(nèi)存碎片化而引入的結(jié)構(gòu)
retain
只是是retained變量+1
release
當(dāng)retained變量大于0時(shí)候-1,當(dāng)?shù)扔?的時(shí)候調(diào)用dealloc實(shí)例方法
1.2.4 蘋(píng)果alloc/retain/release/dealloc 的實(shí)現(xiàn)
+alloc
+allocWithZone
class_createInstance
calloc
__CFDoExternRefOperation函數(shù)
蘋(píng)果就是采用散列表(引用計(jì)數(shù)表)來(lái)管理引用計(jì)數(shù)夕膀。
- 對(duì)比GNUstep和蘋(píng)果兩種管理引用計(jì)數(shù)的方式
1.2.5 autorelease
1.2.6 GNUstep的autorelease實(shí)現(xiàn)
IMP 緩存
在GNUstep中虚倒,實(shí)際NSAutoreleasePool的addObject使用的是鏈表
1.2.7 蘋(píng)果的autorelease實(shí)現(xiàn)
1.3 ARC規(guī)則
1.3.1
同一個(gè)程序中可以以文件為單位設(shè)置ARC有效/無(wú)效
1.3.3 所有權(quán)修飾符
第二章 Blocks
第三章 GCD
3.1 什么是GCD
使用GCD一般就兩個(gè)步驟:
獲取隊(duì)列
調(diào)用方法,將任務(wù)添加進(jìn)隊(duì)列中
3.2 什么是多線程
線程:
多線程:
一個(gè)CPU反復(fù)在多個(gè)線程間切換产舞,就好像多個(gè)線程可以并列執(zhí)行一樣魂奥,而在具有多個(gè)CPU核的情況下,就可以真的提供多個(gè)CPU核并行執(zhí)行多個(gè)線程了
多線程問(wèn)題:
數(shù)據(jù)競(jìng)爭(zhēng)易猫、死鎖耻煤、消耗大量?jī)?nèi)存
3.3 GCD的API
Dispatch Queue
:執(zhí)行處理的等待隊(duì)列,分兩種
Serial DispatchQueue
:串行隊(duì)列 等待現(xiàn)在執(zhí)行中處理結(jié)束
Concurrent Dispatch Queue
:并行隊(duì)列 不等待現(xiàn)在執(zhí)行中處理結(jié)束
Dispatch Queue
和線程的關(guān)系:
主線程中的隊(duì)列是Main Dispatch Queue
,因?yàn)橹骶€程只有一個(gè)准颓,所以Main Dispatch Queue
自然就是 Serial Dispatch Queue
(我的理解:隊(duì)列是用來(lái)派發(fā)任務(wù)的哈蝇,而線程是用來(lái)處理任務(wù)的)
一旦生成Serial DispatchQueue
并追加處理,系統(tǒng)對(duì)于一個(gè)Serial DispatchQueue
就只生成并使用一個(gè)線程攘已。如果生成2000個(gè)Serial DispatchQueue
炮赦,那么就生成2000個(gè)線程。所以Serial DispatchQueue
的生成個(gè)數(shù)應(yīng)當(dāng)僅限所必須的數(shù)量样勃。如果過(guò)多使用多線程吠勘,就會(huì)大量消耗內(nèi)存,引起大量的上下文切換峡眶,大幅度降低系統(tǒng)的響應(yīng)性能剧防。
XNU內(nèi)核決定Concurrent Dispatch Queue
應(yīng)該使用的線程數(shù)量
得到Dispatch Queue
的方法
- 創(chuàng)建
/*
參數(shù)一:線程名,一般那采用 逆序域名
參數(shù)二:NULL代表生成Serial DispatchQueue辫樱,生成Concurrent Dispatch Queue需指定為DISPATCH_QUEUE_CONCURRENT
*/
dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.example.gcd.myConcurrentDispatchQueue",DISPATCH_QUEUE_CONCURRENT);
注意:對(duì)于最低sdk版本>=iOS6.0來(lái)說(shuō),GCD對(duì)象已經(jīng)納入了ARC的管理范圍,我們就不需要再手工調(diào)用 dispatch_release
了
- 獲取系統(tǒng)標(biāo)準(zhǔn)提供的
Dispatch Queue
Main Dispatch Queue
屬于Serial DispatchQueue
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
Global Dispatch Queue
所有的應(yīng)用程序都能使用的Concurrent Dispatch Queue
dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
Global Dispatch Queue
的4個(gè)執(zhí)行優(yōu)先級(jí):
高優(yōu)先級(jí):DISPATCH_QUEUE_PRIORITY_HIGH
默認(rèn)優(yōu)先級(jí):DISPATCH_QUEUE_PRIORITY_DEFAULT
低優(yōu)先級(jí):DISPATCH_QUEUE_PRIORITY_LOW
后臺(tái)優(yōu)先級(jí):DISPATCH_QUEUE_PRIORITY_BACKGROUND
3.2.4 變更隊(duì)列的優(yōu)先級(jí)和執(zhí)行層次dispatch_set_target_queue
變更隊(duì)列優(yōu)先級(jí)
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的優(yōu)先級(jí)峭拘,使之和globalDispatchQueueBackground相同
dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);
變更執(zhí)行層次
如果在多個(gè)Serial Dispatch Queue
中用dispatch_set_target_queue
函數(shù)指定目標(biāo)為某一個(gè)Serial Dispatch Queue
棚唆,那么原先應(yīng)該并行執(zhí)行的多個(gè)Serial Dispatch Queue
,在目標(biāo)Serial Dispatch Queue
上只能同時(shí)執(zhí)行一個(gè)處理心例。
3.2.5 指定時(shí)間追加到Dispatch Queue
,dispatch_after
/*
dispatch_time() 用于計(jì)算相對(duì)時(shí)間
第一個(gè)參數(shù):指定開(kāi)始時(shí)間
第二個(gè)參數(shù):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.");
})
// 用于計(jì)算絕對(duì)時(shí)間
dispatch_walltime
注意:dispatch_after
并不是在指定時(shí)間后執(zhí)行處理,而是在指定時(shí)間追加處理到Dispatch Queue
3.2.6 Dispatch Group
在追加到Dispatch Queue
中的多個(gè)處理全部結(jié)束后止后,想執(zhí)行結(jié)束處理
dispatch_quque_t queue
dispatch_group_notify(group,dispatch_get_main_queue(),^{
NSLog()@"done";
});
// 相比dispatch_group_notify多了一個(gè)超時(shí)時(shí)間
dispatch_group_wait
3.2.7 dispatch_barrier_async
3.2.8 dispatch_sync
串行隊(duì)列中(包括主隊(duì)列)瞎惫,同步嵌套會(huì)造成死鎖
dispatch_barrier_sync
3.2.9 dispatch_apply
代替for循環(huán)