類
分類的作用辕翰?
- 聲明私有方法藐守,分解體積挪丢。
分類的特點(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)用棧
分類中關(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ǔ)在同一容器中越除。
通知實(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呆躲。异逐。。歼秽。应役。。
完整的數(shù)據(jù)結(jié)構(gòu)關(guān)系
類對(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ū)
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件豌。
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
retainCount實(shí)現(xiàn):
1.在Sidetables對(duì)象指針找到對(duì)應(yīng)的SideTable曾掂。
2.聲明result
3.找到對(duì)應(yīng)的引用計(jì)數(shù)
4.進(jìn)行位移運(yùn)算賦值
-
dealloc實(shí)現(xiàn):
-
objc_dipose實(shí)現(xiàn):
-
object_destructInstance實(shí)現(xiàn):
-
clearDeallocating實(shí)現(xiàn):
弱引用管理
-
__weak修飾后會(huì)轉(zhuǎn)化為objc_initWeak.
一個(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_enter
和dispatch_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)前視圖范圍)
-
事件流程圖
視圖響應(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)生丟幀注益。
優(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)方法
繪制流程圖:
異步繪制
-
通過(guò)實(shí)現(xiàn) layer.delegate displayLayer 負(fù)責(zé)生成對(duì)應(yīng)的bitmap,操作layer.contents
在子線程中異步繪制好后 啤月,回到主線程layer設(shè)置Contents
離屏渲染
-
在屏渲染
在當(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é)-懂車)