2021-iOS面試整理

分類的作用辕翰?

  • 聲明私有方法藐守,分解體積挪丢。
    分類的特點(diǎn)?
  • 運(yùn)行時(shí)決議卢厂,可以為系統(tǒng)類添加分類
    分類可以添加哪些內(nèi)容乾蓬?
    分類可以添加實(shí)例方法和類方法
    分類添加屬性,根據(jù)數(shù)據(jù)結(jié)構(gòu)默認(rèn)不能添加實(shí)例變量慎恒,需要通過(guò)關(guān)聯(lián)對(duì)象來(lái)實(shí)現(xiàn) 任内。

分類的加載調(diào)用棧

image.png

分類中關(guān)聯(lián)對(duì)象存儲(chǔ)?

  • 由AssociationManger管理并在AssociationHashMap(key-被關(guān)聯(lián)對(duì)象的指針值融柬,Value-ObjectAssociationMap)存儲(chǔ)死嗦,一個(gè)對(duì)象可以添加多個(gè)關(guān)聯(lián)值,因此采用ObjectAssociationMap存儲(chǔ)粒氧。所有關(guān)聯(lián)對(duì)象存儲(chǔ)在同一容器中越除。


    image.png

通知實(shí)現(xiàn)的機(jī)制?

  • 通知全局維護(hù)的一個(gè)字典:key為通知名稱:value為ObserverList(通過(guò)一個(gè)名稱添加多個(gè)監(jiān)聽(tīng))外盯,ObserverList存儲(chǔ)這通知回調(diào)的方法以及參數(shù)等等摘盆。

KVO的概念

  • 觀察者設(shè)計(jì)模式的一種實(shí)現(xiàn),使用isa混寫(isa-swizzling)來(lái)實(shí)現(xiàn)KVO门怪。
  • 原實(shí)例對(duì)象的指針isa指向 - NSKVONotifying_A通過(guò)重寫Setter來(lái)實(shí)現(xiàn)監(jiān)聽(tīng)。

手動(dòng)KVO如何實(shí)現(xiàn)的锅纺?

  • 對(duì)稱成員變量直接賦值無(wú)法觸發(fā)KVO掷空,在賦值前后分別設(shè)置willChangeValue,didChangeValue。

屬性關(guān)鍵字坦弟?
三種關(guān)鍵字:讀寫權(quán)限护锤,原子性,引用計(jì)數(shù)酿傍。

  • atomic:保證賦值烙懦,獲取是線程安全的,不代表操赤炒。對(duì)數(shù)組進(jìn)行操作是無(wú)法保證線程安全
    assign和weak的區(qū)別氯析?
  • assign:修飾基本類型,修飾對(duì)象不改變引用計(jì)數(shù)莺褒,懸垂對(duì)象指針(對(duì)象銷毀后掩缓,指針依然指向原地址)。
  • weak:不改變修飾對(duì)象的引用計(jì)數(shù)遵岩,對(duì)象釋放后會(huì)自動(dòng)設(shè)置為nil
    深淺拷貝
  • 可變對(duì)象copy和mutableCopy都是深拷貝
  • 不可變對(duì)象的copy是淺拷貝你辣,mutableCopy是深拷貝
  • copy對(duì)象返回的都是不可變對(duì)象。

分類和擴(kuò)展的區(qū)別尘执?

  • 擴(kuò)展:編譯時(shí)決議舍哄,生命在.m文件中,不能為系統(tǒng)類增加擴(kuò)展
  • 分類:運(yùn)行時(shí)決議誊锭,可以為系統(tǒng)類增加擴(kuò)展表悬。

了解過(guò)類簇么?類簇的優(yōu)勢(shì)在哪里炉旷?

  • 管理了一組隱藏在公共接口下的私有類签孔,NSNumber,UIbutton窘行,對(duì)外部暴露隱藏在通用接口之下的與實(shí)現(xiàn)相關(guān)的類饥追,方便維護(hù)和拓展,具體的實(shí)現(xiàn)代碼放在對(duì)應(yīng)的子類里

如果分類和元類有相同方法罐盔,會(huì)先執(zhí)行哪個(gè)但绕?如果有多個(gè)分類呢?

  • 分類方法合并到方法列表中惶看,根據(jù)源碼所知捏顺,原類方法和分類方法會(huì)優(yōu)先調(diào)用分類方法,如果多個(gè)分類有相同方法纬黎,后編譯分類方法會(huì)優(yōu)先調(diào)用(源碼attachCategories中幅骄,先編譯的文件分類文件會(huì)放到數(shù)組的末端)

查詢方法時(shí),快速查找有序方法列表是按照什么規(guī)則排序的本今?

  • 按照方法的地址大小來(lái)排序的(源碼fixupMethodList方法)

RunLoop(你想要的基本都有)

http://www.reibang.com/p/719aa97078b5

Autorelease和AutoreleasePool

autorelease對(duì)象在什么時(shí)候釋放

  • autorelease對(duì)象的釋放在不同場(chǎng)景下釋放的時(shí)機(jī)不一樣(顯式和隱式)
    autorelease對(duì)象直接是由@autorelasepool{}包裹拆座,那么autorelease對(duì)象會(huì)在@autorelasepool{}的大括號(hào)之后釋放主巍,ARC下自動(dòng)補(bǔ)全release。
    沒(méi)有顯式使用@autorelasepool{}挪凑,會(huì)根據(jù)某次Runloop循環(huán)中調(diào)用_objc_autoreleasePoolPop()釋放(可能是在runloop休眠之前或者退出runloop時(shí))
    使用autorelease和@autoreleasePool的區(qū)別
    第一個(gè)是加到當(dāng)前池里面 等待run loop 釋放孕索,第二個(gè)是新開(kāi)辟一個(gè)自動(dòng)釋放池。

使用@autoreleasePool的工作原理躏碳?

  • 1.首先會(huì)將POOL_BOUNDARY(一個(gè)nil對(duì)象)入棧搞旭,并返回當(dāng)前壓入棧中的地址值,用作 pop 時(shí)的終點(diǎn)
  • 2.調(diào)用到 AutoreleasePoolPage 的 autoreleaseFast 函數(shù)菇绵,添加到 page 中肄渗。
  • 3.在objc_autoreleasePoolPop函數(shù)調(diào)用時(shí)會(huì)將POOL_BOUNDARY的地址值傳入,用作自動(dòng)釋放池pop的停止邊界
    page邊界處理
  • 如果存在page脸甘、且未滿會(huì)直接通過(guò)next指針將對(duì)象地址存放在next中,存在page恳啥。
  • 如果page 存在且滿了,會(huì)創(chuàng)建一個(gè)新的page再壓入POOL_BOUNDARY,再添加autorelease對(duì)象丹诀,然后通過(guò)parent 和 child將上下兩個(gè)page關(guān)聯(lián)
  • 如果page都不存在那么會(huì)創(chuàng)建一個(gè)新的page钝的、壓入POOL_BOUNDARY后再添加autorelease對(duì)象。

Runtime

如果A和B交換了方法铆遭,C在不知情的情況下又和A交換了方法硝桩,會(huì)有什么問(wèn)題,如何避免此問(wèn)題枚荣?

  • 可以交換成功碗脊,A和C交換后, A方法執(zhí)行的C方法橄妆,B執(zhí)行的A方法衙伶,C執(zhí)行的B方法,在原來(lái)的基礎(chǔ)上再調(diào)用C的方法害碾,因?yàn)镃現(xiàn)在持有的是B的方法矢劲,還要再調(diào)用一下本身

objc_object,objc_class
objc_object:
id類型,isa_t(共用體)慌随,isa相關(guān)信息芬沉,引用計(jì)數(shù)啊相關(guān)
objc_class:
Class類型,繼承自objc_object阁猜,包含(Class-SuperClass丸逸,cache_t-cache,class_data_bits_t-bits)
isa指針
共用體結(jié)構(gòu)剃袍,分為指針型isa(代表Class地址)和非指針型isa(isa的值的部分代表Class地址)黄刚。
isa指向:
實(shí)例對(duì)象isa指向Class(調(diào)用對(duì)象方法是從類對(duì)象查找),
類對(duì)象isa指向Meta-Class(調(diào)用類方法是從元類對(duì)象查找)民效。

cache_t
快速查找方法執(zhí)行函數(shù)憔维,可擴(kuò)容的哈希表結(jié)構(gòu)侍芝,局部性原理(增加命中)。
cache_t底層結(jié)構(gòu):bucket_t類型:key,IMP.

class_data_bits_t

  • class_data_bits_t對(duì)class_rw_t的封裝埋同。
  • class_rw_t代表了類的相關(guān)的讀寫信息,對(duì)class_ro_t的封裝
  • class_ro_t代表類相關(guān)的只讀信息棵红。

class_rw_t

  • class_rw_t結(jié)構(gòu):class_ro_t凶赁,protocols,properties逆甜,methods
  • protocols虱肄,properties,methods都是二維數(shù)組來(lái)實(shí)現(xiàn)的(比如N個(gè)分類交煞,分類中有N個(gè)方法因此采用二維數(shù)組)咏窿。

class_ro_t

  • class_ro_t結(jié)構(gòu):name,ivars素征,properties集嵌,protocols,methodList
  • ivars御毅,properties根欧,protocols,methodList都是一位數(shù)組端蛆。

method_t

  • method_t結(jié)構(gòu):SEL-name(名稱)凤粗,const char*-types(參數(shù)和返回值),IMP-imp(無(wú)類型的函數(shù)指針)今豆。
  • types解析:返回值嫌拣,參數(shù)1,參數(shù)2呆躲。异逐。。歼秽。应役。。


    image.png

完整的數(shù)據(jù)結(jié)構(gòu)關(guān)系

image.png

類對(duì)象和元類對(duì)象的關(guān)系

  • 類對(duì)象存儲(chǔ)實(shí)例方法列表等信息
  • 元類對(duì)象存儲(chǔ)類方法列表等信息

一個(gè)NSObject分類文件燥筷,.h聲明+(void)test,.m實(shí)現(xiàn)-(void)test,調(diào)用+(void)test方法箩祥。是否崩潰,為什么肆氓?

  • 調(diào)用的類方法在元類對(duì)象找不到的時(shí)候袍祖,會(huì)通過(guò)superClass逐級(jí)想父類查找,最終找到根元類谢揪,根元類superClass又會(huì)指向根類蕉陋,調(diào)用根類的方法捐凭,即實(shí)例方法,因此不會(huì)崩潰凳鬓。

消息傳遞
objc_msgSend(接受者茁肠,選擇器)。
struct objc_super: receiver指向當(dāng)前對(duì)象(self缩举,而不是super)垦梆。
super class : objc_msSendSuper(super,@selector(class))

方法查找
*緩存查找: 給定SEL找對(duì)應(yīng)bucket_t中IMP。通過(guò)哈希查找:通過(guò)哈希算法和mask進(jìn)行位與運(yùn)算仅孩。

  • 有序查找:對(duì)已經(jīng)排序好的列表進(jìn)行二分查找托猩。、
  • 無(wú)序查找:對(duì)于沒(méi)有排序的列表辽慕,采用一般遍歷查找京腥。
  • 父類逐級(jí)查找:通過(guò)superClass的指向找到父類,父類繼續(xù)通過(guò)緩存溅蛉,有序公浪,無(wú)序查找。

消息轉(zhuǎn)發(fā)流程

  • 動(dòng)態(tài)方法解析:resolveInstanceMethod船侧,返回Yes處理完成
  • 目標(biāo)重定向:進(jìn)行fowaringTargetForSeletor因悲,通過(guò)別的類執(zhí)行。
  • 最后補(bǔ)救:methodSignatureForSelctor勺爱,
  • 通過(guò)簽名調(diào)用:forwardInvocation晃琳。

內(nèi)存管理

內(nèi)存布局分區(qū)

image.png

stack:方法調(diào)用
heap:通過(guò)alloc分配
bss:未初始化全局變量
data:已初始化的全局標(biāo)量
text:程序代碼

iOS如何進(jìn)行內(nèi)存管理的?
TaggedPointer(小對(duì)象)
NONPOINTER_ISA(64位比特位琐鲁,存儲(chǔ)isa用不到64卫旱,多余的部分存儲(chǔ)了內(nèi)存管理的內(nèi)容(非指針類型的ISA))
散列表:(弱引用表,引用計(jì)數(shù)表)

SideTables了解么围段?

  • SideTables:自旋鎖顾翼,引用計(jì)數(shù)標(biāo)(RefcountMap),弱引用表(weak_table_t)奈泪。

為什么會(huì)有多個(gè)SideTable組成

  • 如果一張表會(huì)存在效率問(wèn)題适贸,在不同線程中,進(jìn)行操作涝桅,需要進(jìn)行加鎖處理拜姿,影響效率。
  • 分離鎖計(jì)數(shù)方案冯遂,吧引用計(jì)數(shù)表拆分蕊肥,分別加鎖,不同線程同時(shí)操作蛤肌,可以執(zhí)行并發(fā)操作壁却。

如何實(shí)現(xiàn)快速分流批狱?

  • sideTables本質(zhì)是一張Hash表,Key為對(duì)象指針展东,通過(guò)hash運(yùn)行找到對(duì)應(yīng)的sideTable赔硫。
  • 通過(guò)內(nèi)存地址通過(guò)和數(shù)組的取余運(yùn)算得到下標(biāo)。

sideTable數(shù)據(jù)結(jié)構(gòu)

  • 自旋鎖:忙等鎖盐肃,適合輕量訪問(wèn)卦停。
  • 引用計(jì)數(shù)表:RefcountMap,通過(guò)對(duì)象的指針找到對(duì)象的引用計(jì)數(shù)恼蓬。避免循環(huán)遍歷,提高效率僵芹。
  • weak_table_:本質(zhì)也是hash表处硬,通過(guò)對(duì)象指針,經(jīng)過(guò)hash算法找到拇派,弱引用存儲(chǔ)的位置weak_entry_t,存儲(chǔ)這弱引用指針荷辕。

ARC的特點(diǎn):

  • ARC是LLVM和Runtime協(xié)作的結(jié)果
  • ARC禁止手動(dòng)調(diào)用
  • ARC增加了weak,strong件豌。
image.png
image.png

retain實(shí)現(xiàn):
1.在Sidetables對(duì)象指針找到對(duì)應(yīng)的SideTable疮方。
2.再通過(guò)引用計(jì)數(shù)變量和指針,找到對(duì)應(yīng)的引用計(jì)數(shù)值茧彤。
3.進(jìn)行+1

release實(shí)現(xiàn):
1.在Sidetables對(duì)象指針找到對(duì)應(yīng)的SideTable骡显。
2.再通過(guò)對(duì)象指針,找到對(duì)應(yīng)的引用計(jì)數(shù)表
3.進(jìn)行-1


image.png

retainCount實(shí)現(xiàn):
1.在Sidetables對(duì)象指針找到對(duì)應(yīng)的SideTable曾掂。
2.聲明result
3.找到對(duì)應(yīng)的引用計(jì)數(shù)
4.進(jìn)行位移運(yùn)算賦值


image.png
  • dealloc實(shí)現(xiàn):


    image.png
  • objc_dipose實(shí)現(xiàn):


    image.png
  • object_destructInstance實(shí)現(xiàn):


    image.png
  • clearDeallocating實(shí)現(xiàn):


    image.png

弱引用管理

  • __weak修飾后會(huì)轉(zhuǎn)化為objc_initWeak.


    image.png

    一個(gè)修飾__weak通過(guò)編譯會(huì)轉(zhuǎn)換成objc_initWeak,執(zhí)行storeWeak惫谤,最后通過(guò)weak_register_no_lock進(jìn)行弱引用變量的添加,添加的位置通過(guò)hash算法進(jìn)行查找珠洗,如果有弱引用數(shù)組溜歪,直接插入,如果沒(méi)有創(chuàng)建许蓖。


循環(huán)引用的種類蝴猪?

  • 自循環(huán)引用,相互循環(huán)引用膊爪,多循環(huán)引用自阱。

如何破除循環(huán)引用和方案?

  • 避免產(chǎn)生循環(huán)引用
  • 在合適時(shí)機(jī)手動(dòng)斷環(huán)
    方案:__weak,__block

NSTimer解決循環(huán)引用的方式米酬?
創(chuàng)建一個(gè)中間對(duì)象弱引用原對(duì)象和NSTimer动壤,NSTimer的實(shí)現(xiàn)是在中間對(duì)象實(shí)現(xiàn)的。

多線程

NSOperation和NSOperationQueue有什么優(yōu)勢(shì)和特點(diǎn)

  • 添加任務(wù)依賴( [bp1 addDependency:bp2]),前者依賴后者淮逻,bp2先執(zhí)行琼懊。
    *任務(wù)執(zhí)行狀態(tài)的控制:
    四種狀態(tài):isReady阁簸,isExecuting,isFinished哼丈,isCancel
    重寫main方法和start方法启妹,main方法底層控制變更任務(wù)完成狀態(tài)以及退出,重寫start方法自行控制任務(wù)狀態(tài)醉旦。
    底層變更狀態(tài)通過(guò)KVO監(jiān)聽(tīng)饶米。
  • 控制最大并發(fā)量
    NSThread的啟動(dòng)流程
    start() - 創(chuàng)建pthread - main() - [performSelector] - exit()

iOS常用鎖有哪些?

  • synchronize车胡,atomic檬输,OSSplinkLock(自旋鎖),NSLock匈棘,NSRecursiveLock(遞歸鎖)丧慈,信號(hào)量
    自旋鎖和互斥鎖的特點(diǎn)?
    自旋鎖-循環(huán)等待主卫,不釋放當(dāng)前資源逃默,輕量級(jí)的訪問(wèn)。
    NSLock重復(fù)加鎖的問(wèn)題簇搅?如何解決完域?
    會(huì)產(chǎn)生死鎖,使用遞歸鎖(NSRecursiveLock)

串行隊(duì)列瘩将,并行隊(duì)列吟税,同步,異步

  • pragma mark --主隊(duì)列
    主線程執(zhí)行同步任務(wù)會(huì)死鎖:同步任務(wù)在添加進(jìn)線程后就要當(dāng)即執(zhí)行姿现,主線程正在執(zhí)行當(dāng)前函數(shù)乌妙,相互等待。

主線程執(zhí)行異步任務(wù):不會(huì)開(kāi)新的線程建钥,會(huì)在主線程依次執(zhí)行任務(wù)藤韵。主隊(duì)列添加完成block以后直接返回,主隊(duì)列是順序添加的block熊经,block按照f(shuō)ifo執(zhí)行泽艘。

  • pragma mark --并發(fā)隊(duì)列

并發(fā)隊(duì)列執(zhí)行同步任務(wù):不創(chuàng)建線程,有序的執(zhí)行所有的任務(wù)镐依。這些任務(wù)都是創(chuàng)建一個(gè)就立馬執(zhí)行匹涮,執(zhí)行完才創(chuàng)建下一個(gè)。同步函數(shù)是不會(huì)添加線程的槐壳,并發(fā)隊(duì)列與否然低,并不影響同步函數(shù)的創(chuàng)建,因?yàn)楸旧砭筒荒芏鄤?chuàng)建線程,也就不存在并發(fā)雳攘。

并發(fā)隊(duì)列執(zhí)行異步任務(wù):創(chuàng)建新的線程带兜,各個(gè)線程也是并發(fā)執(zhí)行的。

  • pragma mark --串行隊(duì)列

串行隊(duì)列執(zhí)行同步任務(wù):不會(huì)創(chuàng)建線程吨灭,順序執(zhí)行任務(wù)刚照。block任務(wù)執(zhí)行完成以后繼續(xù)向下執(zhí)行任務(wù)。

串行隊(duì)列執(zhí)行異步任務(wù)(與主隊(duì)列一樣):不會(huì)開(kāi)新的線程喧兄,block任務(wù)會(huì)在主線程依次執(zhí)行任務(wù)无畔。主隊(duì)列添加完成block以后直接返回繼續(xù)執(zhí)行下面的任務(wù),主隊(duì)列是順序添加的block吠冤,block按照f(shuō)ifo執(zhí)行浑彰。

信號(hào)量打印

- (void)semaphoreTest {
    dispatch_semaphore_t signal = dispatch_semaphore_create(1);
    
    __block long x = 0;
    NSLog(@"0x:%ld",x);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(1);
        NSLog(@"w1");
        x = dispatch_semaphore_signal(signal);
        NSLog(@"1x:%ld",x);
        
        sleep(2);//睡兩秒
        NSLog(@"w2");
        x = dispatch_semaphore_signal(signal);
        NSLog(@"2x:%ld",x);
    });
 
    x = dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
    NSLog(@"3x:%ld",x);
    
    x = dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
    NSLog(@"w3");
    NSLog(@"4x:%ld",x);
    
    x = dispatch_semaphore_wait(signal, DISPATCH_TIME_FOREVER);
    
    NSLog(@"w4");
    NSLog(@"5x:%ld",x);
}
  • 打印順序:0x,3x拯辙,w1郭变,1x,w3薄风,4x,w2拍嵌,2x遭赂,w4,5x横辆,w的打印會(huì)存在異步的浮動(dòng) 信號(hào)量的執(zhí)行順序是確定的 0x,3x,1x,4x,2x,5x

如果一個(gè)線程組中3個(gè)線程為異步操作, 線程組能否匯總?cè)蝿?wù)撇他,如果不能有什么解決方案?

  • 如果加了異步操作就無(wú)法匯總狈蚤,會(huì)先調(diào)用Notify中的方法
  • 使用組中的dispatch_group_enterdispatch_group_leave即可處理困肩,或者使用信號(hào)量dispatch_semaphore_t
  • 正確的方法應(yīng)該下邊兩個(gè)函數(shù)一起來(lái)使用脆侮,這樣才能實(shí)現(xiàn)我們想要的最終效果:
    dispatch_group_enter(dispatch_group_t group)
    dispatch_group_leave(dispatch_group_t group)
  • 參數(shù)group不能為空锌畸,在異步任務(wù)成功返回后調(diào)用
  • 它明確的表明了一個(gè) block 被加入到了隊(duì)列組group中,此時(shí)group中的任務(wù)的引用計(jì)數(shù)會(huì)加1(類似于OC的內(nèi)存管理)靖避,leave 是 -1
  • 當(dāng)隊(duì)列組里的任務(wù)的引用計(jì)數(shù)等于0時(shí)潭枣,會(huì)調(diào)用dispatch_group_notify函數(shù)。
- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //創(chuàng)建一個(gè)group
    __block dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建一個(gè)隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //group任務(wù)計(jì)數(shù)加3
    dispatch_group_enter(group);
    dispatch_group_enter(group);
    dispatch_group_enter(group);
    
    //創(chuàng)建一個(gè)GCD線程1
    dispatch_group_async(group, queue, ^{
            //模擬異步耗時(shí)操作
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10000; i ++) {}
            NSLog(@"線程1");
            //group任務(wù)計(jì)數(shù)減1
            dispatch_group_leave(group);
        });
    });
    
    //創(chuàng)建一個(gè)GCD線程2
    dispatch_group_async(group, queue, ^{
        //模擬異步耗時(shí)操作
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10000; i ++) {}
            NSLog(@"線程2");
            //group任務(wù)計(jì)數(shù)減1
            dispatch_group_leave(group);
        });
    });
    
    //創(chuàng)建一個(gè)GCD線程3
    dispatch_group_async(group, queue, ^{
        //模擬異步耗時(shí)操作
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10000; i ++) {}
            NSLog(@"線程3");
            //group任務(wù)計(jì)數(shù)減1
            dispatch_group_leave(group);
        });
    });
    
    //創(chuàng)建一個(gè)group通知, 任務(wù)計(jì)數(shù)為0時(shí)自動(dòng)調(diào)用
    dispatch_group_notify(group, queue, ^{
        NSLog(@"結(jié)束");
    });
}
  • 使用信號(hào)量來(lái)解決的方案幻捏?
- (void)viewDidLoad {
    
    [super viewDidLoad];
    //創(chuàng)建一個(gè)group
    __block dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建一個(gè)隊(duì)列
    __block dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //創(chuàng)建一個(gè)信號(hào)量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    //創(chuàng)建一個(gè)GCD線程1
    dispatch_group_async(group, queue, ^{
        //模擬異步耗時(shí)操作
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10000; i ++) { }
            NSLog(@"線程1");
            //完成迭代后, 增加信號(hào)量
            dispatch_semaphore_signal(semaphore);
        });
        
        //在迭代完成之前, 信號(hào)量等待
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    
    //創(chuàng)建一個(gè)GCD線程2
    dispatch_group_async(group, queue, ^{
        
        //模擬異步耗時(shí)操作
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10000; i ++) {}
            NSLog(@"線程2");
            //完成迭代后, 增加信號(hào)量
            dispatch_semaphore_signal(semaphore);
        });
        
        //在迭代完成之前, 信號(hào)量等待
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    
    //創(chuàng)建一個(gè)GCD線程3
    dispatch_group_async(group, queue, ^{
        
        //模擬異步耗時(shí)操作
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10000; i ++) { }
            NSLog(@"線程3");
            //完成迭代后, 增加信號(hào)量
            dispatch_semaphore_signal(semaphore);
        });
        
        //在迭代完成之前, 信號(hào)量等待
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    
    //創(chuàng)建一個(gè)group通知, 任務(wù)計(jì)數(shù)為0時(shí)自動(dòng)調(diào)用
    dispatch_group_notify(group, queue, ^{
        NSLog(@"結(jié)束");
    });
}

使用信號(hào)量盆犁,不同線程相互干擾,如何處理篡九?

  • 每個(gè)線程分別創(chuàng)建自己的信號(hào)量即可谐岁。
    GCD實(shí)現(xiàn)異步任務(wù)同步除了線程組還能使用方式?
  • dispatch_barrier_async,以及上面的兩種方法伊佃。

三方框架(AF窜司,SD)

AFNetworking2.X為什么需要常駐線程?

  • 首先需要在子線程去start connection锭魔,請(qǐng)求發(fā)送后例证,所在的子線程需要保活以保證正常接收到 NSURLConnectionDelegate 回調(diào)方法迷捧。如果每來(lái)一個(gè)請(qǐng)求就開(kāi)一條線程织咧,并且保活線程漠秋,這樣開(kāi)銷太大了笙蒙。所以只需要保活一條固定的線程庆锦,在這個(gè)線程里發(fā)起請(qǐng)求捅位、接收回調(diào)。

AFNetworking3.0后為什么不再需要常駐線程搂抒?
NSURLSession發(fā)起的請(qǐng)求艇搀,不再需要在當(dāng)前線程進(jìn)行代理方法的回調(diào)!可以指定回調(diào)的delegateQueue求晶,這樣我們就不用為了等待代理回調(diào)方法而苦苦保活線程了芳杏。

operationQueue.maxConcurrentOperationCount =1在3.0中需要 矩屁?
AF3.0的operationQueue是用來(lái)接收NSURLSessionDelegate回調(diào)的,鑒于一些多線程數(shù)據(jù)訪問(wèn)的安全性考慮爵赵,設(shè)置了maxConcurrentOperationCount = 1來(lái)達(dá)到串行回調(diào)的效果`吝秕。
而AF2.0的operationQueue是用來(lái)添加operation并進(jìn)行并發(fā)請(qǐng)求的,所以不要設(shè)置為1空幻。

Swift

swift中的class和struct區(qū)別烁峭?

  • 屬性初始化的不同,struct可直接在構(gòu)造函數(shù)中初始化屬性秕铛, class不可直接在構(gòu)造函數(shù)中初始化,要用帶參數(shù)的構(gòu)造方法
  • 變量賦值方式不同,值拷貝和引用拷貝
  • 可變與不可變內(nèi)容:struct使用let和var甄別则剃,class不具備這一特性。
  • struct 的 function 要去改變 property 的值的時(shí)候要加上 mutating如捅,而 class 不用
  • struct不能繼承棍现,class可以繼承。
  • struct分配在棧中镜遣,class分配在堆中己肮。

swift中struct的優(yōu)勢(shì)和劣勢(shì)在哪里士袄?
優(yōu)勢(shì):

  • 數(shù)據(jù)安全:因?yàn)?Struct 是用值類型傳遞的,它們沒(méi)有引用計(jì)數(shù)谎僻。
  • 內(nèi)存安全:由于他們沒(méi)有引用數(shù)娄柳,他們不會(huì)因?yàn)檠h(huán)引用導(dǎo)致內(nèi)存泄漏。
  • 速度優(yōu)勢(shì):值類型通常來(lái)說(shuō)是以棧的形式分配的艘绍,而不是用堆赤拒。因此他們比 Class 要快。
  • 拷貝斟酌: OC 里拷貝一個(gè)對(duì)象,你必須選用正確的拷貝類型(深拷貝诱鞠、淺拷貝),而struct不需要擔(dān)心挎挖。
  • 線程安全:值類型是自動(dòng)線程安全的。無(wú)論你從哪個(gè)線程去訪問(wèn)你的 Struct 航夺,都非常簡(jiǎn)單蕉朵。
    劣勢(shì):
  • OC與swift混編無(wú)法使用
  • Struct 不能被序列化成 NSData 對(duì)象。
  • Struct 不能相互繼承阳掐。
    如果模型較小始衅,并且無(wú)需繼承、無(wú)需儲(chǔ)存到 NSUserDefault 或者無(wú)需 Objective-C 使用時(shí)缭保,建議使用 Struct汛闸。

UI相關(guān):

tableView數(shù)據(jù)源同步的問(wèn)題?

  • 并發(fā)訪問(wèn):主線程進(jìn)行了數(shù)據(jù)源的操作艺骂,將操作同步給子線程诸老,進(jìn)行刷新
  • 串行訪問(wèn):子線程請(qǐng)求一組數(shù)據(jù),主線程進(jìn)行了數(shù)據(jù)增刪進(jìn)行等待彻亲,子線程請(qǐng)求完成后孕锄,同步數(shù)據(jù)吮廉,刷新UI(耗時(shí)體驗(yàn))

UIView和CALayer的區(qū)別苞尝?為什么要這樣設(shè)計(jì)?

  • UIView提供內(nèi)容宦芦,以及負(fù)責(zé)交互事件的處理宙址,參與響應(yīng)鏈的訪問(wèn)
  • CALayer提供展示內(nèi)容
  • 保證單一職責(zé)原則,展示和交互各自負(fù)責(zé)

事件傳遞

  • 事件傳遞主要是和兩個(gè)方法有關(guān)hitTest和pointInside(視圖響應(yīng)和是否在當(dāng)前視圖范圍)
  • 事件流程圖


    image.png

視圖響應(yīng)鏈的流程

  • 繼承于UIResponder调卑,nextResponder是下一個(gè)響應(yīng)者

UI卡頓丟幀原因以及方案

  • VSyn垂直信號(hào) 一秒60幀
  • CPU做視圖的布局工作抡砂,GPU進(jìn)行圖層渲染
  • 在規(guī)定的時(shí)間內(nèi),下一幀VSyn信號(hào)到來(lái)前未完成CPU和GPU的圖片合成工作恬涧,因此產(chǎn)生丟幀注益。
    image.png

    優(yōu)化方案
    CPU:
  • 對(duì)象創(chuàng)建,調(diào)整溯捆,銷毀放在子線程操作
  • 預(yù)排版(布局計(jì)算丑搔,文本計(jì)算)放在子線程
  • 預(yù)渲染(文本異步繪制,圖片解碼)
    GPU:
  • 避免離屏渲染
  • 視圖混合
    UIView繪制原理
  • setNeedsDisplay - 調(diào)用layer.setNeedsDisplay(臟標(biāo)記) - Layer.display - 響應(yīng)方法
    繪制流程圖:


    image.png

    image.png

異步繪制

  • 通過(guò)實(shí)現(xiàn) layer.delegate displayLayer 負(fù)責(zé)生成對(duì)應(yīng)的bitmap,操作layer.contents
    在子線程中異步繪制好后 啤月,回到主線程layer設(shè)置Contents


    image.png

離屏渲染

  • 在屏渲染在當(dāng)前屏幕渲染煮仇,指的是GPU的渲染操作是在當(dāng)前用于顯示屏幕緩沖區(qū)中進(jìn)行
  • 離屏渲染指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開(kāi)辟的一個(gè)緩沖區(qū)進(jìn)行渲染
    設(shè)置UI視圖某些屬性(圓角),在未預(yù)合成之前不能直接顯示的就會(huì)觸發(fā)離屏渲染谎仲。
    離屏渲染觸發(fā)的場(chǎng)景
  • 圓角和maskToBounds一起使用
  • 圖層蒙版
  • 陰影
    離屏渲染觸發(fā)的場(chǎng)景
    離屏渲染會(huì)增加GPU的工作量浙垫,會(huì)導(dǎo)致CPU和GPU總耗時(shí)超過(guò)16.7ms,即丟幀或者卡頓

iOS拓展問(wèn)題:

動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)的區(qū)別郑诺,以及鏈接過(guò)程夹姥?

  • 靜態(tài)庫(kù):以.a 和 .framework為文件后綴名。
  • 動(dòng)態(tài)庫(kù):以.tbd(之前叫.dylib) 和 .framework 為文件后綴名间景。
  • 區(qū)別
    靜態(tài)庫(kù):鏈接時(shí)會(huì)被完整的復(fù)制到可執(zhí)行文件中佃声,被多次使用就有多份拷貝。
    動(dòng)態(tài)庫(kù):鏈接時(shí)不復(fù)制倘要,程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)加載到內(nèi)存圾亏,系統(tǒng)只加載一次,多個(gè)程序共用(如系統(tǒng)的UIKit.framework等)封拧,節(jié)省內(nèi)存志鹃。
  • 庫(kù)的鏈接過(guò)程
    鏈接一個(gè)庫(kù)的3個(gè)必要條件:
    -I(大寫i):在指令目錄尋找頭文件 (xc setting:header search path)
    -L:指定鏈接的庫(kù)文件路徑 (.a/.dylib)(xc setting: Libary search path)
    -l(小寫L):指定鏈接庫(kù)文件的名稱(xc setting:other linker flags)

Macho文件如何生成的?

  • LLVM預(yù)處理代碼 -> LLVM 進(jìn)行詞法語(yǔ)法分析 -> LLVM生成AST -> AST 會(huì)生成 IR -> IR 生成的可執(zhí)行文件就是 Mach-O
    Macho的結(jié)構(gòu)泽西?
    Header (頭部)
    用于快速確認(rèn)該文件的CPU類型曹铃、文件類型等信息
    LoadCommands (加載命令)
    用于告訴loader如何設(shè)置并加載二進(jìn)制數(shù)據(jù)
    Data (數(shù)據(jù)段 segment)
    存放數(shù)據(jù):代碼、字符常量捧杉、類陕见、方法等
    可以擁有多個(gè)segment,每個(gè)segment可以有零到多個(gè)section味抖。每個(gè)段都有一段虛擬地址映射到進(jìn)程的地址空間
    Loader Info (鏈接信息)
    一個(gè)完整的用戶級(jí)MachO文件的末端是一系列鏈接信息评甜。其中包含了動(dòng)態(tài)加載器用來(lái)鏈接可執(zhí)行文件或者依賴所需使用的符號(hào)表、字符串表等

網(wǎng)絡(luò)

HTTPS的加載流程仔涩?
1.客戶端發(fā)送一些隨機(jī)數(shù)忍坷,和加密算法,通過(guò)tcp發(fā)送給服務(wù)端熔脂。
2.服務(wù)端得到信息后通過(guò)私鑰解密返回給客戶端(返回SSL證書(shū)的版本號(hào)佩研,公鑰進(jìn)行非對(duì)稱加密,隨機(jī)數(shù))
3.需要驗(yàn)證服務(wù)端返回的證書(shū)是否合法
4.客戶端會(huì)生成預(yù)主秘鑰
5.預(yù)主秘鑰加上兩個(gè)隨機(jī)數(shù) 進(jìn)行公鑰加密 霞揉,再回傳給服務(wù)端旬薯。
6.服務(wù)端會(huì)進(jìn)行私鑰解密,獲取預(yù)主密鑰
7.最后進(jìn)行對(duì)稱加密進(jìn)行信息交互 适秩。
非對(duì)稱加密流程绊序,(通過(guò)公鑰算不出私鑰些侍,發(fā)送后進(jìn)行私鑰解密),耗時(shí)只驗(yàn)證身份使用非對(duì)稱加密政模,驗(yàn)證通過(guò)后進(jìn)行對(duì)稱加密通信岗宣。

算法,數(shù)據(jù)結(jié)構(gòu)

鏈表的數(shù)組的使用場(chǎng)景淋样?(字節(jié)-懂車)

  • 數(shù)組應(yīng)用場(chǎng)景:數(shù)據(jù)比較少耗式;經(jīng)常做的運(yùn)算是按序號(hào)訪問(wèn)數(shù)據(jù)元素;數(shù)組更容易實(shí)現(xiàn)趁猴,任何高級(jí)語(yǔ)言都支持刊咳;構(gòu)建的線性表較穩(wěn)定。

  • 鏈表應(yīng)用場(chǎng)景:對(duì)線性表的長(zhǎng)度或者規(guī)模難以估計(jì)儡司;頻繁做插入刪除操作娱挨;構(gòu)建動(dòng)態(tài)性比較強(qiáng)的線性表。

二叉樹(shù) 按層次遍歷 (字節(jié)-懂車)

用底層設(shè)計(jì)內(nèi)存 緩存 捕犬,最大為40MB跷坝,以及超過(guò)40MB處理機(jī)制 (字節(jié)-懂車)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碉碉,隨后出現(xiàn)的幾起案子柴钻,更是在濱河造成了極大的恐慌,老刑警劉巖垢粮,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贴届,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蜡吧,警方通過(guò)查閱死者的電腦和手機(jī)毫蚓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)昔善,“玉大人元潘,你說(shuō)我怎么就攤上這事∫唬” “怎么了柬批?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵匠童,是天一觀的道長(zhǎng)空厌。 經(jīng)常有香客問(wèn)我德撬,道長(zhǎng),這世上最難降的妖魔是什么洛姑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮皮服,結(jié)果婚禮上楞艾,老公的妹妹穿的比我還像新娘参咙。我一直安慰自己,他們只是感情好硫眯,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布蕴侧。 她就那樣靜靜地躺著,像睡著了一般两入。 火紅的嫁衣襯著肌膚如雪净宵。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天裹纳,我揣著相機(jī)與錄音择葡,去河邊找鬼。 笑死剃氧,一個(gè)胖子當(dāng)著我的面吹牛敏储,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朋鞍,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼已添,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了滥酥?” 一聲冷哼從身側(cè)響起酝碳,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恨狈,沒(méi)想到半個(gè)月后疏哗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡禾怠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年返奉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吗氏。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芽偏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弦讽,到底是詐尸還是另有隱情污尉,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布往产,位于F島的核電站被碗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏仿村。R本人自食惡果不足惜锐朴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蔼囊。 院中可真熱鬧焚志,春花似錦衣迷、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至膳沽,卻和暖如春佃迄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贵少。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工呵俏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人滔灶。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓普碎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親录平。 傳聞我的和親對(duì)象是個(gè)殘疾皇子麻车,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345