《編寫高質(zhì)量OC代碼》已順利完成一二三四五六七八篇艾船!
附上鏈接:
iOS 編寫高質(zhì)量Objective-C代碼(一)—— 簡(jiǎn)介
iOS 編寫高質(zhì)量Objective-C代碼(二)—— 面向?qū)ο?/a>
iOS 編寫高質(zhì)量Objective-C代碼(三)—— 接口和API設(shè)計(jì)
iOS 編寫高質(zhì)量Objective-C代碼(四)—— 協(xié)議與分類
iOS 編寫高質(zhì)量Objective-C代碼(五)—— 內(nèi)存管理機(jī)制
iOS 編寫高質(zhì)量Objective-C代碼(六)—— block專欄
iOS 編寫高質(zhì)量Objective-C代碼(七)—— GCD專欄
iOS 編寫高質(zhì)量Objective-C代碼(八)—— 系統(tǒng)框架
本篇的主題是iOS中的 “ 大中樞開(kāi)發(fā) GCD ”。
先簡(jiǎn)單介紹一下今天的主角:GCD
。
- GCD(
Grand Central Dispatch
):一種與塊相關(guān)的技術(shù)耻卡,提供了對(duì)線程的抽象管理(基于派發(fā)隊(duì)列dispatch queue
)跟磨。GCD會(huì)根據(jù)系統(tǒng)資源情況暇榴,適時(shí)且高效地 “創(chuàng)建線程” 蟀淮、“復(fù)用線程” 蚪腐、 “銷毀線程”宝踪。
一侨糟、多用派發(fā)隊(duì)列,少用同步鎖
問(wèn):在iOS開(kāi)發(fā)中瘩燥,如何通過(guò)鎖來(lái)提供同步機(jī)制秕重?(以前面試中,經(jīng)常問(wèn)道的問(wèn)題..)
答:在GCD出現(xiàn)之前厉膀,有兩種方式:
- 同步塊:
@synchronized(self) {...}
- (void)synchronizedMethod {
@synchronized (self) {
// Safe area...
}
}
- NSLock:
[_lock lock];
&[_lock unlock];
_lock = [[NSLock alloc] init];
- (void)synchronizedMethod {
[_lock lock];
// Safe area..
[_lock unlock];
}
不過(guò)這兩種寫法效率很低溶耘,如果有很多屬性二拐,那么每個(gè)屬性的同步塊都要等其他同步塊執(zhí)行完畢才能執(zhí)行。
GCD出現(xiàn)后凳兵,GCD與Block相結(jié)合百新,使開(kāi)發(fā)變得更加簡(jiǎn)單、高效庐扫。
問(wèn):如何保證屬性讀寫時(shí)線程絕對(duì)安全饭望?
答:在屬性寫入時(shí),使用柵欄塊barrier
形庭。只有當(dāng)前所有并發(fā)塊都執(zhí)行完畢后铅辞,才會(huì)執(zhí)行barrier
塊,然后才會(huì)繼續(xù)向下處理萨醒。
- 思路如下:
- 代碼如下:
_syncQueue = dispatch_queue_create("syncQueue", DISPATCH_QUEUE_CONCURRENT);
//! 讀取字符串
- (NSString *)someString {
__block NSString *localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString;
}
- (void)setSomeString:(NSString *)someString {
dispatch_barrier_async(_syncQueue, ^{
_someString = someString;
});
}
二斟珊、多用GCD,少用performSelector系列方法
performSelector
系列方法的缺點(diǎn)有兩個(gè):
-
performSelector
系列方法可能引起內(nèi)存泄漏:
在ARC環(huán)境下富纸,編譯器并不知道將要調(diào)用的選擇子是什么囤踩,有沒(méi)有返回值,返回值是什么胜嗓,所以ARC不能判斷返回值是否能釋放高职,因此ARC做了一個(gè)比較謹(jǐn)慎的做法:只添加retain
,不添加release
辞州。因此在有返回值或參數(shù)的時(shí)候可能導(dǎo)致內(nèi)存泄漏怔锌。 -
performSelector
系列方法的返回值只能是void或OC對(duì)象類型。 -
performSelector
系列方法最多只能傳入兩個(gè)參數(shù)变过。
因此可以使用GCD來(lái)代替performSelector
系列方法:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//do something..
});
三埃元、掌握GCD及操作隊(duì)列的使用時(shí)機(jī)
GCD
性能很棒,但在執(zhí)行后臺(tái)任務(wù)時(shí)媚狰,GCD
并不一定是最佳選擇岛杀。在iOS開(kāi)發(fā)中,還有一種技術(shù)叫NSOperationQueue
崭孤。GCD
是基于C語(yǔ)言的API类嗤,性能較高。而NSOperationQueue
是基于GCD
的抽象辨宠。
使用NSOperation
和NSOperationQueue
的優(yōu)點(diǎn):
支持取消某個(gè)
NSOperation
:
在運(yùn)行任務(wù)前遗锣,可以在NSOperation對(duì)象上調(diào)用cancel方法,用以表明此任務(wù)不需要執(zhí)行嗤形。不過(guò)已經(jīng)啟動(dòng)的任務(wù)無(wú)法取消精偿。iOS 8之前,GCD隊(duì)列是無(wú)法取消的,GCD是“安排好之后就不管了(fire and forget)”笔咽。iOS 8之后搔预,支持dispatch_cancel
和dispatch_block_cancel
;NSOperation
支持多任務(wù)操作的依賴關(guān)系:
比如:任務(wù)A叶组、B拯田、C必須在任務(wù)D完成后執(zhí)行。支持通過(guò)
KVO
監(jiān)控NSOperation
對(duì)象的屬性:
例如:可以通過(guò)isCancelled
屬性來(lái)判斷任務(wù)是否已取消扶叉,通過(guò)isFinished
屬性來(lái)判斷任務(wù)是否已經(jīng)完成等等勿锅;支持指定
NSOperationQueue
的優(yōu)先級(jí):
操作的優(yōu)先級(jí)表示此操作與隊(duì)列中其他操作之間的優(yōu)先關(guān)系帕膜,優(yōu)先級(jí)高的NSOperationQueue
先執(zhí)行枣氧,優(yōu)先級(jí)低的后執(zhí)行。GCD的隊(duì)列也有優(yōu)先級(jí)垮刹,不過(guò)不是針對(duì)整個(gè)隊(duì)列的达吞;重用
NSOperation
對(duì)象:
在開(kāi)發(fā)中你可以使用NSOperation
的子類或者自己創(chuàng)建NSOperation
對(duì)象來(lái)保存一些信息,可以在類中定義方法荒典,使得代碼能夠多次使用酪劫;
四、通過(guò)Dispatch Group機(jī)制寺董,根據(jù)系統(tǒng)資源狀況來(lái)執(zhí)行任務(wù)
dispatch group
是GCD
的一項(xiàng)特性覆糟,能夠把任務(wù)進(jìn)行分組管理,然后等待這組任務(wù)執(zhí)行完畢時(shí)會(huì)有通知遮咖,開(kāi)發(fā)者可以拿到結(jié)果然后繼續(xù)下一步操作滩字。
另外,通過(guò)dispatch group
在并發(fā)隊(duì)列上同時(shí)執(zhí)行多項(xiàng)任務(wù)的時(shí)候御吞,GCD會(huì)根據(jù)系統(tǒng)資源狀態(tài)來(lái)幫忙調(diào)度這些并發(fā)執(zhí)行的任務(wù)麦箍。
五、使用dispatch_once來(lái)執(zhí)行只需要運(yùn)行一次的線程安全代碼
例如:我們開(kāi)發(fā)中寫一個(gè)單例陶珠,就可以使用dispatch_once
:
+ (instancetype)sharedInstance {
static Class *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[Class alloc] init];
});
return manager;
}
六挟裂、不要使用dispatch_get_current_queue
理由如下:
-
dispatch_get_current_queue
函數(shù)的行為常常與開(kāi)發(fā)者所預(yù)期的不同,此函數(shù)已經(jīng)廢棄揍诽,只應(yīng)做調(diào)試之用诀蓉。 - 由于
GCD
是按層級(jí)來(lái)組織的,所以無(wú)法單用某個(gè)隊(duì)列對(duì)象來(lái)描述"當(dāng)前隊(duì)列"這一概念暑脆。 -
dispatch_get_current_queue
函數(shù)用于解決由不可以重入的代碼所引發(fā)的死鎖渠啤,然后能用此函數(shù)解決的問(wèn)題,通常也可以用"隊(duì)列特定數(shù)據(jù)"來(lái)解決饵筑。