序
在百度三面被掛掉之后项栏,沉下心來(lái)浦辨,整理構(gòu)建自己的開(kāi)發(fā)體系,方便以后查看沼沈。 金三銀四已經(jīng)降臨流酬,為此提供了找了不少學(xué)習(xí)方向給大家,也是一些進(jìn)價(jià)方向列另,希望能幫大家快速提升自己的短板芽腾!
本章節(jié):
- 百度三面被掛掉之后,沉下心來(lái)總結(jié)页衙,構(gòu)建自己的iOS開(kāi)發(fā)體系(上)
- 百度三面被掛掉之后摊滔,沉下心來(lái)總結(jié),構(gòu)建自己的iOS開(kāi)發(fā)體系(下)待更新請(qǐng)關(guān)注
標(biāo):不要浪費(fèi)美好的年華拷姿,做自己覺(jué)得對(duì)的事情!
目錄
- 一旱函、設(shè)計(jì)原則响巢、設(shè)計(jì)模式
- 二、內(nèi)存管理
- 三棒妨、多線程
- 四踪古、Block
- 五含长、Runtime
- 六、Runloop
- 七伏穆、KVO
- 八拘泞、KVC
- 九、Category
- 十枕扫、網(wǎng)絡(luò)
- 十一陪腌、UI
- 十二、其他
- 十三烟瞧、OC對(duì)象相關(guān)
2021年【最新iOS開(kāi)發(fā)面試題】感謝觀看贈(zèng)資料:
下載地址:
一诗鸭、設(shè)計(jì)原則、設(shè)計(jì)模式
1参滴、六大設(shè)計(jì)基本原則
定義:一個(gè)類只負(fù)責(zé)一件事
優(yōu)點(diǎn):類的復(fù)雜度降低强岸、可讀性增強(qiáng)、易維護(hù)砾赔、變更引起的風(fēng)險(xiǎn)降低
應(yīng)用:系統(tǒng)提供的UIView和CALayer的關(guān)系:UIView負(fù)責(zé)時(shí)間傳遞蝌箍、事件響應(yīng);CALayer負(fù)責(zé)動(dòng)畫(huà)及展示
定義:對(duì)修改關(guān)閉暴心、對(duì)擴(kuò)展開(kāi)放
- 設(shè)計(jì)的類做好后就不再修改妓盲,如果有新的需求,通過(guò)新加類的方式來(lái)滿足酷勺,而不去修改現(xiàn)有的類的代碼
優(yōu)點(diǎn):靈活本橙、穩(wěn)定(不需修改內(nèi)部代碼,使得被破壞的程度大大下降)
關(guān)鍵:抽象化
使用:
- 我們可以把把行為添加到一個(gè)協(xié)議中脆诉,使用時(shí)遵守這個(gè)協(xié)議即可甚亭。
- 添加類目(Category)方式創(chuàng)建
定義:所有引用父類的地方必須能透明地使用其子類的對(duì)象。
- 通俗點(diǎn)說(shuō)就是击胜,父類可以被子類無(wú)縫替換亏狰,且原有功能不受任何影響
優(yōu)點(diǎn):
- 代碼共享,減少創(chuàng)建類的工作量偶摔,每個(gè)子類都擁有父類的所有屬性和方法
- 提高代碼的可重用性暇唾、擴(kuò)張性,項(xiàng)目的開(kāi)放性
缺點(diǎn):程序的可移植性降低辰斋,增加了對(duì)象間的耦合性
定義:抽象不應(yīng)該依賴于具體實(shí)現(xiàn)策州,具體實(shí)現(xiàn)可以依賴于抽象
核心思想:面向接口編程
優(yōu)點(diǎn):代碼結(jié)構(gòu)清晰,維護(hù)容易
實(shí)例:平時(shí)我們使用 protocol 匿名對(duì)象模式就是依賴倒置原則的最好體現(xiàn)
定義:客戶端不應(yīng)該依賴它不需要的接口
- 使用多個(gè)專門(mén)的協(xié)議宫仗、而不是一個(gè)龐大臃腫的協(xié)議够挂。
- 協(xié)議中的方法應(yīng)當(dāng)盡量少
例:UITableViewDataSource、UITableViewDelegate
優(yōu)點(diǎn):解耦藕夫、增強(qiáng)可讀性孽糖、可擴(kuò)展性枯冈、可維護(hù)性
定義:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象有盡可能少的了解办悟。
- 也就是說(shuō)尘奏,如果兩個(gè)類不必彼此直接通信,那么這兩個(gè)類就不應(yīng)當(dāng)發(fā)生直接的相互作用病蛉。
迪米特法則應(yīng)用:
- 外觀模式(Facade)
- 中介者模式(Mediator)
- 匿名對(duì)象
優(yōu)點(diǎn):使對(duì)象之間的耦合降到最底炫加,從而使得類具有很好的可讀性和可維護(hù)性。
特點(diǎn)總結(jié)
- 單一職責(zé)原則主要說(shuō)明:類的職責(zé)要單一
- 里氏替換原則強(qiáng)調(diào):不要破壞繼承體系
- 依賴倒置原則描述要:面向接口編程
- 接口隔離原則講解:設(shè)計(jì)接口的時(shí)候要精簡(jiǎn)
- 迪米特法則告訴我們:要降低耦合
- 開(kāi)閉原則講述的是:對(duì)擴(kuò)展開(kāi)放铡恕,對(duì)修改關(guān)閉
- 設(shè)計(jì)模式
TODO(待填充);??????????
二琢感、內(nèi)存管理
規(guī)則
- 在iOS中,使用 “引用計(jì)數(shù)” 來(lái)管理OC對(duì)象的內(nèi)存
- 新創(chuàng)建的OC對(duì)象探熔,引用計(jì)數(shù)是1驹针;
- 調(diào)用retain會(huì)讓OC對(duì)象的引用計(jì)數(shù)+1,調(diào)用release會(huì)讓OC對(duì)象的引用計(jì)數(shù)-1
- 當(dāng)引用計(jì)數(shù)減為0诀艰,OC對(duì)象就會(huì)銷毀柬甥,釋放占用的內(nèi)存空間
- 當(dāng)調(diào)用 alloc、new其垄、copy苛蒲、mutableCopy 方法返回了一個(gè)對(duì)象,在不需要這個(gè)對(duì)象時(shí)绿满,要調(diào)用release或者aoturelease釋放
2臂外、引用計(jì)數(shù)怎么存儲(chǔ)?
- 可以直接存儲(chǔ)在isa指針中
- 如果不夠存儲(chǔ)的話喇颁,會(huì)存儲(chǔ)在SideTable結(jié)構(gòu)體的refcnts散列表中
struct SideTable {
spinlock_t stock;
RefcountMap refcnts; // 存放著對(duì)象引用計(jì)數(shù)的散列表
weak_table_t weak_table;
}
3漏健、ARC具體為引用計(jì)數(shù)做了哪些工作?
- 編譯階段自動(dòng)添加代碼
ARC是LLVM編譯器和Runtime系統(tǒng)相互協(xié)作的一個(gè)結(jié)果
- 編譯器幫我們實(shí)現(xiàn)內(nèi)存管理相關(guān)的代碼
- Runtime在程序運(yùn)行過(guò)程中處理弱引用
4橘霎、深拷貝與淺拷貝
概念:
- 深拷貝:內(nèi)容拷貝蔫浆,產(chǎn)生新的對(duì)象
- 淺拷貝:指針拷貝,沒(méi)有產(chǎn)生新的對(duì)象姐叁,原對(duì)象的引用計(jì)數(shù)+1
- 完全拷貝:深拷貝的一種瓦盛,能拷貝多層內(nèi)容(使用歸解檔技術(shù))
執(zhí)行結(jié)果:
- copy:不可變拷貝,產(chǎn)生不可變副本
- mutableCopy:可變拷貝外潜,產(chǎn)生可變副本
準(zhǔn)則:不可變對(duì)象的copy方法是淺拷貝原环,其余都是深拷貝??????????
原因:
- 它是不可變對(duì)象,沒(méi)有必要拷貝一份出來(lái)处窥,指向同一塊地址還節(jié)省內(nèi)存
- 不可變對(duì)象調(diào)用copy返回他本身嘱吗,不可變對(duì)象copy就相當(dāng)于是retain
1、對(duì)象的拷貝
- 遵守協(xié)議(<NSCopying, NSMutableCopying>)
- 實(shí)現(xiàn)協(xié)議方法
- (id)copyWithZone:(NSZone *)zone {
Person *person = [Person allocWithZone:zone];
person.name = self.name;
return person;
}
- (id)mutableCopyWithZone:(NSZone *)zone {
Person *person = [Person allocWithZone:zone];
person.name = self.name;
return person;
}
2碧库、集合對(duì)象的拷貝
- 對(duì)于集合類的可變對(duì)象來(lái)說(shuō)柜与,深拷貝并非嚴(yán)格意義上的深復(fù)制,只能算是單層深復(fù)制
- 即雖然新開(kāi)辟了內(nèi)存地址嵌灰,但是存放在內(nèi)存上的值(也就是數(shù)組里的元素仍然之鄉(xiāng)員數(shù)組元素值弄匕,并沒(méi)有另外復(fù)制一份),這就叫做單層深復(fù)制
- 對(duì)于集合類的對(duì)象如何實(shí)現(xiàn)每一層都深拷貝呢沽瞭?(1迁匠、initWithArray:copyItems、2驹溃、歸檔解檔技術(shù))
#import <Foundation/Foundation.h>
@interface Person : NSObject <NSCoding>
@property (nonatomic, copy) NSString *name;
@end
#import "Person.h"
@implementation Person
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self.name = [aDecoder decodeObjectForKey:@"name"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.name forKey:@"name"];
}
@end
歸檔和解檔的概念補(bǔ)充:
有時(shí)存在這樣的需求城丧,即將程序中使用的多個(gè)對(duì)象及其屬性值,以及它們的相互關(guān)系保存到文件中豌鹤,或者發(fā)送給另外的進(jìn)程亡哄。為了實(shí)現(xiàn)此功能,foundation框架中布疙,可以把相互關(guān)聯(lián)的多個(gè)對(duì)象歸檔為二進(jìn)制文件蚊惯,而且還能將對(duì)象的關(guān)系從二進(jìn)制文件中還原出來(lái)。
5灵临、weak指針實(shí)現(xiàn)原理截型,SideTable的結(jié)構(gòu)是什么樣?
- iOS 中 weak 的實(shí)現(xiàn)原理
- iOS 底層解析weak的實(shí)現(xiàn)原理
- weak的生命周期:具體實(shí)現(xiàn)方法
- SideTable結(jié)構(gòu)
1儒溉、常用知識(shí)點(diǎn):
- 所引用對(duì)象的計(jì)數(shù)器不會(huì)+1宦焦,并在引用對(duì)象被釋放的時(shí)候自動(dòng)被設(shè)置為nil
- 通常用于解決循環(huán)引用問(wèn)題
2、weak指針實(shí)現(xiàn)原理
- Runtime維護(hù)了一個(gè)weak表顿涣,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak指針波闹。
- weak表其實(shí)就是一個(gè)哈希表,key:對(duì)象的內(nèi)存地址园骆;value:指向該對(duì)象的所有弱引用的指針
- 當(dāng)對(duì)象銷毀的時(shí)候舔痪,通過(guò)對(duì)象的地址值,取出對(duì)象的弱引用表锌唾,將表里面的弱引用清除
3锄码、為什么弱引用不會(huì)導(dǎo)致循環(huán)引用?
- 沒(méi)有增加引用計(jì)數(shù)
4晌涕、SideTable的結(jié)構(gòu)是什么樣的?
struct SideTable {
// 保證原子操作的自旋鎖
spinlock_t slock;
// 引用計(jì)數(shù)的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
};
5滋捶、weak屬性如何自動(dòng)置nil的? 具體到如何查找的余黎?
TODO(待填充);??????????
6重窟、自動(dòng)釋放池相關(guān)
1、以下代碼輸出什么惧财?會(huì)有什么問(wèn)題巡扇?
for (int i = 0; i < 1000000; i ++) {
NSString *string = @"Abc";
string = [string lowercaseString];
// string = [string stringByAppendingString:@"xyz"];
string = [string stringByAppendingFormat:@"xyz"];
NSLog(@"%d-%@", i, string);
}
問(wèn)題解析:
- 每執(zhí)行一次循環(huán)扭仁,就會(huì)有一個(gè)string加到當(dāng)前NSRunloop中的自動(dòng)釋放池中
- 只有當(dāng)自動(dòng)釋放池被release的時(shí)候,自動(dòng)釋放池中的標(biāo)示了autorelease的這些數(shù)據(jù)所占用的內(nèi)存空間才能被釋放掉
- 當(dāng)someLargeNumber大到一定程度時(shí)厅翔,內(nèi)存空間將被耗盡而沒(méi)有被釋放掉乖坠,所以就出現(xiàn)了內(nèi)存溢出的現(xiàn)象。
解決方案:在循環(huán)里面加個(gè)自動(dòng)釋放池
for (int i = 0; i < 1000000; i ++) {
@autoreleasepool {
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingFormat:@"xyz"];
NSLog(@"%d-%@", i, string);
}
}
2刀闷、自動(dòng)釋放池底層結(jié)構(gòu):
- AutoreleasPool是通過(guò)以AutoreleasePoolPage為結(jié)點(diǎn)的 “雙向鏈表” 來(lái)實(shí)現(xiàn)的
3熊泵、AutoreleasPool運(yùn)行的三個(gè)過(guò)程:
- objc_autoreleasePoolPush()
- [objc autorelease]
- objc_autoreleasePoolPop(void *)
objc_autoreleasePoolPush()
- 調(diào)用的AutoreleasePoolPage的push函數(shù)
- 一個(gè)push操作其實(shí)就是創(chuàng)建一個(gè)新的Autoreleasepool
- 對(duì)應(yīng)AutoreleasePoolPage的具體實(shí)現(xiàn)就是往AutoreleasePoolPage中的next位置插入一個(gè) POOL_SENTINEL
- 并且返回插入的 POOL_SENTINEL 的內(nèi)存地址。這個(gè)地址也就是我們前面提到的 pool token
- 在執(zhí)行 pop 操作的時(shí)候作為函數(shù)的入?yún)?
push 函數(shù)通過(guò)調(diào)用 autoreleaseFast 函數(shù)來(lái)執(zhí)行具體的插入操作
autoreleaseFast 函數(shù)在執(zhí)行具體的插入操作時(shí)三種情況不同的處理
- 當(dāng)前 page 存在且沒(méi)有滿時(shí)甸昏,直接將對(duì)象添加到當(dāng)前 page 中顽分,即 next 指向的位置;
- 當(dāng)前 page 存在且已滿時(shí)施蜜,創(chuàng)建一個(gè)新的 page 卒蘸,并將對(duì)象添加到新創(chuàng)建的 page 中;
- 當(dāng)前 page 不存在時(shí)翻默,即還沒(méi)有 page 時(shí)悬秉,創(chuàng)建第一個(gè) page ,并將對(duì)象添加到新創(chuàng)建的 page 中
objc_autoreleasePoolPop(void *) 函數(shù)本質(zhì)
- 就是是調(diào)用的 AutoreleasePoolPage 的 pop 函數(shù)
- pop 函數(shù)的入?yún)⒕褪?push 函數(shù)的返回值冰蘑,也就是 POOL_SENTINEL 的內(nèi)存地址和泌,即 pool token 。
- 當(dāng)執(zhí)行 pop 操作時(shí)祠肥,內(nèi)存地址在 pool token 之后的所有 autoreleased 對(duì)象都會(huì)被 release 武氓。
- 直到 pool token 所在 page 的 next 指向 pool token 為止。
TODO(待填充);??????????
4仇箱、autoreleasepool和線程的關(guān)系县恕?
7、Copy剂桥、Strong忠烛、Weak、Assign的區(qū)別权逗?
assign
- 用于對(duì)基本數(shù)據(jù)類型進(jìn)行賦值操作美尸,不更改引用計(jì)數(shù)
- 也可以用來(lái)修飾對(duì)象,但是被assign修飾的對(duì)象在釋放后斟薇,指針的地址還是存在的师坎,指針并沒(méi)有被置為nil,成為野指針
- 之所以可以修飾基本數(shù)據(jù)類型堪滨,因?yàn)榛緮?shù)據(jù)類型一般分配在棧上胯陋,棧的內(nèi)存會(huì)由系統(tǒng)自動(dòng)處理,不會(huì)造成野指針。
weak:
- 修飾Object類型遏乔,修飾的對(duì)象在釋放后义矛,指針地址會(huì)被置為nil,是一種弱引用
- 在ARC環(huán)境下盟萨,為避免循環(huán)引用症革,往往會(huì)把delegate屬性用weak修飾
- weak和strong不同的是:當(dāng)一個(gè)對(duì)象不再有strong類型的指針指向它的時(shí)候,它就會(huì)被釋放鸯旁,即使還有weak型指針指向它,那么這些weak型指針也將被清除量蕊。
strong:
- ARC下的strong等同于MRC下的retain都會(huì)把對(duì)象引用計(jì)數(shù)加1
copy:
- 會(huì)在內(nèi)存里拷貝一份對(duì)象铺罢,兩個(gè)指針指向不同的內(nèi)存地址。
- 一般用來(lái)修飾NSString等有對(duì)應(yīng)可變類型的對(duì)象残炮,因?yàn)樗麄冇锌赡芎蛯?duì)應(yīng)的可變類型(NSMutableString)之間進(jìn)行賦值操作韭赘,為確保可變對(duì)象變化時(shí)势就,對(duì)象中的字符串不被修改 泉瞻,應(yīng)該在設(shè)置屬性時(shí)拷貝一份。
- 而若用strong修飾苞冯,如果可變對(duì)象變化袖牙,對(duì)象中的字符串屬性也會(huì)跟著變化。
1舅锄、block屬性為什么需要用copy來(lái)修飾鞭达?
- 因?yàn)樵贛RC下,block在創(chuàng)建的時(shí)候皇忿,它的內(nèi)存是分配在棧(stack)上的畴蹭,而不是在堆(heap)上,可能被隨時(shí)回收鳍烁。
- 他本身的作于域是屬于創(chuàng)建時(shí)候的作用域叨襟,一旦在創(chuàng)建時(shí)候的作用域外面調(diào)用block將導(dǎo)致程序崩潰。
- 通過(guò)copy可以把block拷貝(copy)到堆幔荒,保證block的聲明域外使用糊闽。
- 在ARC下寫(xiě)不寫(xiě)都行,編譯器會(huì)自動(dòng)對(duì)block進(jìn)行copy操作爹梁。
2墓怀、代理為什么使用weak修飾?
- weak指明該對(duì)象并不負(fù)責(zé)保持delegate這個(gè)對(duì)象卫键,delegate的銷毀由外部控制
- 如果用strong修飾傀履,強(qiáng)引用后外界不能銷毀delegate對(duì)象,會(huì)導(dǎo)致循環(huán)引用
3、為什么NSMutableArray一般不用copy修飾钓账?
- (void)setData:(NSMutableArray *)data {
if (_data != data) {
[_data release];
_data = [data copy];
}
}
拷貝完成后:可變數(shù)組->不可變數(shù)組碴犬,在外操作時(shí)(添加、刪除等)會(huì)存在問(wèn)題
4梆暮、說(shuō)到野指針了服协,什么是“僵尸對(duì)象”?
#[iOS-野指針與僵尸對(duì)象](https://www.cnblogs.com/junhuawang/p/9213093.html)?????
- 一個(gè)OC對(duì)象引用計(jì)數(shù)為0被釋放后就變成僵尸對(duì)象啦粹,僵尸對(duì)象的內(nèi)存已經(jīng)被系統(tǒng)回收
- 雖然可能該對(duì)象還存在偿荷,數(shù)據(jù)依然在內(nèi)存中,但僵尸對(duì)象已經(jīng)是不穩(wěn)定對(duì)象了唠椭,不可以再訪問(wèn)或者使用
- 它的內(nèi)存是隨時(shí)可能被別的對(duì)象申請(qǐng)而占用的
8跳纳、- (void)dealloc底層執(zhí)行了什么?
- (void)dealloc {
_objc_rootDealloc(self);
}
void _objc_rootDealloc(id obj) {
ASSERT(obj);
obj->rootDealloc();
}
inline void objc_object::rootDealloc() {
if (isTaggedPointer()) return; // fixme necessary?
if (fastpath(isa.nonpointer && // 無(wú)優(yōu)化過(guò)isa指針
!isa.weakly_referenced && // 無(wú)弱引用
!isa.has_assoc && // 無(wú)關(guān)聯(lián)對(duì)象
!isa.has_cxx_dtor && // 無(wú)cxx析構(gòu)函數(shù)
!isa.has_sidetable_rc)) { // 不存在引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中(使用 sidetable 來(lái)存儲(chǔ)引用計(jì)數(shù))
// 直接釋放
assert(!sidetable_present());
free(this);
} else {
// 下一步
object_dispose((id)this);
}
}
// 如果不能快速釋放寺庄,則調(diào)用 object_dispose()方法,做下一步的處理
static id _object_dispose(id anObject) {
if (anObject==nil) return nil;
objc_destructInstance(anObject);
anObject->initIsa(_objc_getFreedObjectClass ());
free(anObject);
return nil;
}
void *objc_destructInstance(id obj) {
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor(); // 是否存在析構(gòu)函數(shù)
bool assoc = obj->hasAssociatedObjects(); // 是否有關(guān)聯(lián)對(duì)象
// This order is important.
if (cxx) object_cxxDestruct(obj); // 銷毀成員變量
if (assoc) _object_remove_assocations(obj); // 釋放動(dòng)態(tài)綁定的對(duì)象
obj->clearDeallocating();
}
return obj;
}
/*
* clearDeallocating一共做了兩件事
*
* 1力崇、將對(duì)象弱引用表清空斗塘,即將弱引用該對(duì)象的指針置為nil
* 2、清空引用計(jì)數(shù)表
* - 當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)值過(guò)大(超過(guò)255)時(shí)亮靴,引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫 SideTable 的屬性中
* - 此時(shí)isa的 has_sidetable_rc 值為1馍盟,這就是為什么弱引用不會(huì)導(dǎo)致循環(huán)引用的原因
*/
inline void objc_object::clearDeallocating() {
if (slowpath(!isa.nonpointer)) {
// Slow path for raw pointer isa.
sidetable_clearDeallocating();
}
else if (slowpath(isa.weakly_referenced || isa.has_sidetable_rc)) {
// Slow path for non-pointer isa with weak refs and/or side table data.
clearDeallocating_slow();
}
assert(!sidetable_present());
}
三、多線程
9茧吊、多線程 - GCD相關(guān)
- iOS 多線程:『GCD』詳盡總結(jié) - [行走少年郎]
- GCD中隊(duì)列與任務(wù)嵌套的組合測(cè)試
- iOS gcd線程死鎖問(wèn)題
- GCD信號(hào)量-dispatch_semaphore_t
GCD核心概念:「任務(wù)」朽合、「隊(duì)列」
1、任務(wù):
- 概念:指操作饱狂,線程中執(zhí)行的那段代碼曹步,GCD主要放在block中;
- 執(zhí)行任務(wù)的方式:「同步執(zhí)行」休讳、「異步執(zhí)行」讲婚;
- 區(qū)別:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束,是否具備開(kāi)啟新縣城的能力俊柔;
同步執(zhí)行(sync)
- 同步添加任務(wù)到指定隊(duì)列中筹麸,在添加的任務(wù)執(zhí)行結(jié)束之前,會(huì)一直等待雏婶,直到隊(duì)列里面的任務(wù)完成之后再繼續(xù)執(zhí)行
- 只能在當(dāng)前線程中執(zhí)行任務(wù)物赶,不具備開(kāi)啟新線程的能力
異步執(zhí)行(async)
- 異步添加任務(wù)到指定隊(duì)列中,不會(huì)做任何等待留晚,可以繼續(xù)執(zhí)行任務(wù)
- 可以在新的線程中執(zhí)行任務(wù)酵紫,具備開(kāi)啟新縣城的能力
- ??異步執(zhí)行雖然具有開(kāi)啟新線程的能力,但不一定開(kāi)啟新線程。(與任務(wù)指定的隊(duì)列類型有關(guān))
2奖地、隊(duì)列(Dispatch Queue)
- 概念:執(zhí)行任務(wù)的等待隊(duì)列橄唬,即用來(lái)存放任務(wù)的隊(duì)列
- 結(jié)構(gòu):特殊的線性表,采用FIFO(先進(jìn)先出)原則参歹。即每讀取一個(gè)任務(wù)仰楚,則從隊(duì)列中釋放一個(gè)任務(wù)
串行隊(duì)列:(Serial Dispatch Queue)
- 每次只有一個(gè)任務(wù)被執(zhí)行,任務(wù)依次執(zhí)行(只開(kāi)啟一個(gè)線程犬庇,一個(gè)任務(wù)執(zhí)行完成后僧界,再執(zhí)行下一個(gè)任務(wù))
并發(fā)隊(duì)列:(Concurrent Dispatch Queue)
- 可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行。(可以開(kāi)啟多個(gè)線程臭挽,并且同時(shí)執(zhí)行任務(wù))
- ??并發(fā)隊(duì)列的「并發(fā)」功能只有在異步(dispatch_async)方法下才有效
3捂襟、GCD使用步驟
- 創(chuàng)建一個(gè)隊(duì)列(串行隊(duì)列/并發(fā)隊(duì)列)
- 將任務(wù)追加到任務(wù)的等待隊(duì)列中,然后系統(tǒng)就會(huì)根據(jù)任務(wù)類型執(zhí)行任務(wù)(同步執(zhí)行/異步執(zhí)行)
4埋哟、死鎖條件:
- 使用sync函數(shù)往當(dāng)前串行隊(duì)列中添加任務(wù),會(huì)卡住當(dāng)前的串行隊(duì)列郎汪。
面試題一赤赊、打印順序
NSLog(@"執(zhí)行任務(wù)1");
dispatch_queue_t queue = dispatch_queue_create("com.example.gcd.1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("com.example.gcd.2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"執(zhí)行任務(wù)2");
dispatch_sync(queue2, ^{
NSLog(@"執(zhí)行任務(wù)3");
});
NSLog(@"執(zhí)行任務(wù)4");
});
NSLog(@"執(zhí)行任務(wù)5");
2021-03-01 16:47:46.122744+0800 ZF_Beta[17625:344152] 執(zhí)行任務(wù)1
2021-03-01 16:47:46.122977+0800 ZF_Beta[17625:344152] 執(zhí)行任務(wù)5
2021-03-01 16:47:46.122984+0800 ZF_Beta[17625:344229] 執(zhí)行任務(wù)2
2021-03-01 16:47:46.123171+0800 ZF_Beta[17625:344229] 執(zhí)行任務(wù)3
2021-03-01 16:47:46.123300+0800 ZF_Beta[17625:344229] 執(zhí)行任務(wù)4
dispatch_queue_t ser = dispatch_queue_create("ser", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_async(ser, ^{
NSLog(@"2");
});
NSLog(@"3");
dispatch_sync(ser, ^{
NSLog(@"4");
});
NSLog(@"5");
2021-02-26 11:25:15.703849+0800 ZF_Beta[6156:123418] 1
2021-02-26 11:25:15.704053+0800 ZF_Beta[6156:123418] 3
2021-02-26 11:25:15.704062+0800 ZF_Beta[6156:123698] 2
2021-02-26 11:25:15.704231+0800 ZF_Beta[6156:123418] 4
2021-02-26 11:25:15.704311+0800 ZF_Beta[6156:123418] 5
- (void)viewDidLoad {
[self performSelector:@selector(test3) withObject:nil afterDelay:0];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"---111");
});
NSLog(@"---333");
}
- (void)test3 {
NSLog(@"---222");
}
---333
---111
---222
- (void)viewDidLoad {
[self performSelector:@selector(test1) withObject:nil afterDelay:0];
[self performSelector:@selector(test2) withObject:nil];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"===3");
});
[UIView animateWithDuration:10 animations:^{
NSLog(@"===4");
}];
}
- (void)test1 {
NSLog(@"===1");
}
- (void)test2 {
NSLog(@"===2");
}
2021-03-04 17:41:03.759310+0800 property[25604:424718] ===2
2021-03-04 17:41:03.759642+0800 property[25604:424718] ===4
2021-03-04 17:41:03.788454+0800 property[25604:424718] ===3
2021-03-04 17:41:03.789335+0800 property[25604:424718] ===1
面試題二、如何打造線程安全的NSMutableArray煞赢?
- 線程鎖:使用線程鎖在對(duì)數(shù)組讀寫(xiě)時(shí)候加鎖
- 派發(fā)隊(duì)列:
《Effective Objective 2.0》中41條提出的觀點(diǎn)抛计,串行同步:將讀取和寫(xiě)入都安排在同一個(gè)隊(duì)列里,可保證數(shù)據(jù)同步照筑。
面試題三吹截、如何異步下載多張小圖最后合成一張大圖?
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(), ^{
// 合并圖片
});
面試題四凝危、什么是線程安全波俄?
- 多線程操作過(guò)程中往往都是多個(gè)線程并發(fā)執(zhí)行的,因此同一個(gè)資源可能被多個(gè)線程同時(shí)訪問(wèn)蛾默,造成資源搶奪懦铺。
- 線程安全就是多條線程同時(shí)訪問(wèn)一段代碼,不會(huì)造成數(shù)據(jù)混亂的情況
面試題五支鸡、如何設(shè)置常駐線程冬念?
面試題六、在異步線程發(fā)送通知牧挣,在主線程接收通知急前。會(huì)不會(huì)有什么問(wèn)題?
面試題七瀑构、GCD線程是如何調(diào)度的
面試題八裆针、如何實(shí)現(xiàn)多個(gè)任務(wù)執(zhí)行完后,再統(tǒng)一處理?
- 同步阻塞
- 柵欄函數(shù)
- 線程組
??基于runloop的線程本菘椋活码邻、銷毀與通信:http://www.reibang.com/p/4d5b6fc33519
下一章:百度三面被掛掉之后,沉下心來(lái)總結(jié)另假,構(gòu)建自己的iOS開(kāi)發(fā)體系(下)
小編文章請(qǐng)觀看合集
- 直擊2020——iOS 面試題大全(補(bǔ)充完整版)
- “新”攜程像屋,阿里,騰訊iOS面試常見(jiàn)問(wèn)題合集(附答案)
- 新iOS面試題全集合(目前不斷更新)
- 新iOS開(kāi)發(fā)京東零售的面試題
- iOS開(kāi)發(fā)边篮,跳槽面試應(yīng)該注意的Swift面試題
- iOS某些大廠以及小公司的面試題己莺!
文章來(lái)源作者:強(qiáng)子ly