本人參考GitHub《招聘一個(gè)靠譜的iOS》面試題參考答案(下)
41. 使用系統(tǒng)的某些block api(如UIView的block版本寫動(dòng)畫時(shí)),是否也考慮引用循環(huán)問題?
42. GCD的隊(duì)列(dispatch_queue_t)分哪兩種類型?
43. 如何用GCD同步若干個(gè)異步調(diào)用?(如根據(jù)若干個(gè)url異步加載多張圖片,然后在都下載完成后合成一張整圖)
44. dispatch_barrier_async的作用是什么?
45. 蘋果為什么要廢棄dispatch_get_current_queue?
41. 使用系統(tǒng)的某些block api(如UIView的block版本寫動(dòng)畫時(shí)),是否也考慮引用循環(huán)問題?
系統(tǒng)的某些block api中,UIView的block版本寫動(dòng)畫時(shí)不需要考慮循環(huán)引用。
但也有一些API需要考慮:
循環(huán)引用指雙向的強(qiáng)引用,所以單向的強(qiáng)引用(block強(qiáng)引用self)沒有問題,比如:
[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; } ];
[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.someProperty = xyz; }];
[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification"
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * notification) {
self.someProperty = xyz; }];
這些情況不需要考慮“引用循環(huán)”。
但如果使用一些參數(shù)中可能含有ivar(實(shí)例變量)的系統(tǒng)api,如GCD、NSNotificationCenter就要小心點(diǎn),比如:GCD內(nèi)部如果引用了self,而且GCD的其他參數(shù)是ivar,則要考慮循環(huán)引用:
__weak __typeof__(self) weakSelf = self;
dispatch_group_async(_operationsGroup, _operationsQueue, ^
{
__typeof__(self) strongSelf = weakSelf;
[strongSelf doSomething];
[strongSelf doSomethingElse];
}
);
類似的:
__weak __typeof __(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
object:nil
queue:nil
usingBlock:^(NSNotification *note){
__typeof __(self) strongSelf = weakSelf;
[strongSelf dismissModalViewControllerAnimated:YES];
}];
self-->_observer-->block-->self顯然這也是一個(gè)循環(huán)引用。
42. GCD的隊(duì)列(dispatch_queue_t)分哪兩種類型?
- 串行隊(duì)列Serial Dispatch Queue
- 并行隊(duì)列Concurrent Dispatch Queue
43. 如何用GCD同步若干個(gè)異步調(diào)用?(如根據(jù)若干個(gè)URL異步加載多張圖片,然后在都下載完成后合成一張整圖)
使用Dispatch Group追加block到Global Group Queue,這些block如果全部執(zhí)行完畢,就會(huì)執(zhí)行Main Dispatch Queue中的結(jié)束處理的block。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE)PRIORITY_DEFAULT,0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{/*加載圖片1 */});
dispatch_group_async(group, queue, ^{/*加載圖片2 */});
dispatch_group_async(group, queue, ^{/*加載圖片3 */});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并圖片
});
44. dispatch_barrier_async的作用是什么?
在并行隊(duì)列中,為了保持某些任務(wù)的順序,需要等待一些任務(wù)完成后才能繼續(xù)進(jìn)行,使用barrier來等待之前任務(wù)完成,避免數(shù)據(jù)競爭等問題。dispatch_barrier_async函數(shù)會(huì)等待追加到Concurrent Dispatch Queue并行隊(duì)列中的操作全部執(zhí)行完之后,然后再執(zhí)行dispatch_barrier_async函數(shù)追加的處理,等dispatch_barrier_async追加的處理執(zhí)行結(jié)束之后,Concurrent Dispatch Queue才恢復(fù)之前的動(dòng)作繼續(xù)執(zhí)行。
打個(gè)比方:比如公司周末跟團(tuán)旅游,告訴休息站上,司機(jī)說:大家都去上廁所,速戰(zhàn)速?zèng)Q,上完廁所就上高速。超大的公共廁所,大家同時(shí)去,程序猿很快就結(jié)束了,但程序媛就可能慢一些,即使第一個(gè)人回來,司機(jī)也不會(huì)出發(fā),司機(jī)要等待所有人都回來后,才能出發(fā)。dispatch_barrier_async函數(shù)追加的內(nèi)容就如同“上完廁所就上高速”這個(gè)動(dòng)作。
注意:使用dispatch_barrier_async函數(shù)只能搭配自定義并行隊(duì)列dispatch_queue_t使用,不能使用dispatch_get_global_queue,否則dispatch_barrier_async的作用和dispatch_async的作用一模一樣。
45. 蘋果為什么要廢棄dispatch_get_current_queue?
dispatch_get_current_queue容易造成死鎖。