KVO 實(shí)現(xiàn)原理睛挚?
- 利用
Runtime
動(dòng)態(tài)生成一個(gè)子類祭隔,并且讓instance
對(duì)象的isa
指向這個(gè)全新的子類 - 當(dāng)修改
instance
對(duì)象的屬性時(shí)妆丘,會(huì)調(diào)用Foundation
框架的_NSSetXXXValueAndNotify
函數(shù) ,該函數(shù)里面會(huì)先調(diào)用willChangeValueForKey:
然后調(diào)用父類原來(lái)的setter
方法修改值逝她,最后是didChangeValueForKey:
兢孝。didChangeValueForKey 內(nèi)部會(huì)觸發(fā)監(jiān)聽器(Oberser)的監(jiān)聽方法observeValueForKeyPath:ofObject:change:context:
- 如果需要手動(dòng)觸發(fā)
KVO
窿凤,只需要手動(dòng)調(diào)用willChangeValueForKey:
和didChangeValueForKey:
兩個(gè)方法即可仅偎。
KVC 實(shí)現(xiàn)原理?
setValue:forKey
- 按照
setKey:, _setKey:
順序查找方法 雳殊,找到了就傳遞參數(shù)橘沥,調(diào)用方法。 - 如果沒(méi)有找到相种,就查看
accessInstanceVariablesDirectly
方法(默認(rèn)為 YES)的返回值威恼。 - 如果返回值是 YES,那么按
_key寝并,_isKey箫措,key,iskey
的順序查找成員變量衬潦,找到了直接賦值斤蔓,找不到就調(diào)用setValue:forUnderfinedKey:
方法并拋出異常NSUnknownKeyException。 - 如果返回值是 NO镀岛,就調(diào)用
setValue:forUnderfinedKey:
方法并拋出異常 NSUnknownKeyException弦牡。
valueForKey
- 按照
getKey,key漂羊,isKey, _key
的順序查找方法,找到直接調(diào)用走越。 - 如果沒(méi)有找到椭豫,就查看
accessInstanceVariablesDirectly
方法(默認(rèn)為 YES)的返回值。 - 如果返回值是 YES旨指,那么按
_key赏酥,_isKey,key谆构,iskey
的順序查找成員變量裸扶,找到了直接取值,找不到就調(diào)用setValue:forUnderfinedKey:
方法并拋出異常NSUnknownKeyException搬素。 - 如果返回值是 NO呵晨,就調(diào)用
setValue:forUnderfinedKey:
方法并拋出異常 NSUnknownKeyException。
消息轉(zhuǎn)發(fā)機(jī)制原理熬尺?
- 動(dòng)態(tài)方法解析:
對(duì)象在接收到未知的消息時(shí)摸屠,首先會(huì)調(diào)用所屬類的類方法+resolveInstanceMethod:
或者+resolveClassMethod:
。在這個(gè)方法中猪杭,我們有機(jī)會(huì)為該未知消息新增一個(gè)”處理方法”“餐塘。不過(guò)使用該方法的前提是我們已經(jīng)實(shí)現(xiàn)了該”處理方法”,只需要在運(yùn)行時(shí)通過(guò)
class_addMethod
函數(shù)動(dòng)態(tài)添加到類里面就可以了皂吮。 - 備用接受者:
動(dòng)態(tài)方法解析無(wú)法處理消息戒傻,則會(huì)走備用接受者税手。這個(gè)備用接受者只能是一個(gè)新的對(duì)象,不能是self
本身需纳,否則就會(huì)出現(xiàn)無(wú)限循環(huán)芦倒。如果我們沒(méi)有指定相應(yīng)的對(duì)象來(lái)處理selector
,則應(yīng)該調(diào)用父類的實(shí)現(xiàn)來(lái)返回結(jié)果不翩。 - 完整消息轉(zhuǎn)發(fā):
首先創(chuàng)建NSInvocation
對(duì)象兵扬,把尚未處理的消息有關(guān)的內(nèi)容封于其中,此對(duì)象包括selector
口蝠、目標(biāo)(target
及參數(shù)器钟。在觸發(fā)NSInvocation
對(duì)象時(shí),”消息派發(fā)系統(tǒng)“(message-dispatch sys)將會(huì)把消息指派給目標(biāo)對(duì)象妙蔗。若發(fā)現(xiàn)某個(gè)操作不應(yīng)該是本類來(lái)處理傲霸,就需要調(diào)用父類的同名方法。這樣眉反,繼承體系中的每個(gè)類都有機(jī)會(huì)處理此調(diào)用請(qǐng)求昙啄,直至NSObject
。如果最后調(diào)用了NSObject
的方法寸五,最終該方法就會(huì)繼續(xù)調(diào)用doesNotRecognizeSelector:
拋出異常梳凛,表明 'selector' 未能被處理。
理解 weak 屬性梳杏?
-
Runtime
維護(hù)了一個(gè)weak
表韧拒,用于存儲(chǔ)指向某個(gè)對(duì)象的所有weak
指針。weak
表其實(shí)是一個(gè)hash
(哈希)表秘狞,Key
是所指對(duì)象的地址叭莫,Value
是weak
指針的地址(這個(gè)地址的值是所指對(duì)象的地址)數(shù)組蹈集。 - 初始化時(shí):
runtime
會(huì)調(diào)用objc_initWeak
函數(shù)烁试,初始化一個(gè)新的weak
指針指向?qū)ο蟮牡刂贰?/li> - 添加引用時(shí):
objc_initWeak
函數(shù)會(huì)調(diào)用objc_storeWeak()
函數(shù),objc_storeWeak()
的作用是更新指針指向拢肆,創(chuàng)建對(duì)應(yīng)的弱引用表减响。 - 釋放時(shí),調(diào)用
clearDeallocating
函數(shù)郭怪。clearDeallocating
函數(shù)首先根據(jù)對(duì)象地址獲取所有weak
指針地址的數(shù)組支示,然后遍歷這個(gè)數(shù)組把其中的數(shù)據(jù)設(shè)為nil
,最后從weak
表中刪除并清理對(duì)象的記錄鄙才。
項(xiàng)目中網(wǎng)絡(luò)層如何做安全處理颂鸿?
- 盡量使用
https
:
https
可以過(guò)濾掉大部分的安全問(wèn)題。https
在證書申請(qǐng)攒庵,服務(wù)器配置嘴纺,性能優(yōu)化败晴,客戶端配置上都需要投入精力,所以缺乏安全意識(shí)的開發(fā)人員容易跳過(guò)https
栽渴,或者拖到以后遇到問(wèn)題再優(yōu)化尖坤。https
除了性能優(yōu)化麻煩一些以外其他都比想象中的簡(jiǎn)單,如果沒(méi)精力優(yōu)化性能闲擦,至少在注冊(cè)登錄模塊需要啟用https
慢味,這部分業(yè)務(wù)對(duì)性能要求比較低。 - 不要傳輸明文密碼:
不知道現(xiàn)在還有多少 app 后臺(tái)是明文存儲(chǔ)密碼的墅冷。無(wú)論客戶端纯路,server
還是網(wǎng)絡(luò)傳輸都要避免明文密碼,要使用hash
值寞忿「兄纾客戶端不要做任何密碼相關(guān)的存儲(chǔ),hash
值也不行罐脊。存儲(chǔ)token
進(jìn)行下一次的認(rèn)證定嗓,而且token
需要設(shè)置有效期,使用refreshtoken
去申請(qǐng)新的token
萍桌。 -
post
并不比get
安全:
事實(shí)上宵溅,post
和get
一樣不安全,都是明文上炎。參數(shù)放在queryString
或者body
沒(méi)任何安全上的差別恃逻。在http
的環(huán)境下,使用post
或者get
都需要做加密和簽名處理藕施。 - 不要使用 301 跳轉(zhuǎn):
301 跳轉(zhuǎn)很容易被http
劫持攻擊寇损。移動(dòng)端http
使用 301 比桌面端更危險(xiǎn),用戶看不到瀏覽器地址裳食,無(wú)法察覺(jué)到被重定向到了其他地址矛市。如果一定要使用,確保跳轉(zhuǎn)發(fā)生在https
的環(huán)境下诲祸,而且https
做了證書綁定校驗(yàn)浊吏。 -
http
請(qǐng)求都帶上 MAC:
所有客戶端發(fā)出的請(qǐng)求,無(wú)論是查詢還是寫操作救氯,都帶上MAC(Message AuthenticationCode)找田。MAC 不但能保證請(qǐng)求沒(méi)有被篡改(Integrity),還能保證請(qǐng)求確實(shí)來(lái)自你的合法客戶端(Signing)着憨。當(dāng)然前提是你客戶端的key
沒(méi)有被泄漏墩衙,如何保證客戶端key
的安全是另一個(gè)話題。MAC 值的計(jì)算可以簡(jiǎn)單的處理為hash
(request params+key)。帶上 MAC 之后漆改,服務(wù)器就可以過(guò)濾掉絕大部分的非法請(qǐng)求植袍。MAC 雖然帶有簽名的功能,和 RSA 證書的電子簽名方式卻不一樣籽懦,原因是 MAC 簽名和簽名驗(yàn)證使用的是同一個(gè)key
于个,而 RSA 是使用私鑰簽名,公鑰驗(yàn)證暮顺,MAC 的簽名并不具備法律效應(yīng)厅篓。 -
http
請(qǐng)求使用臨時(shí)密鑰:
高延遲的網(wǎng)絡(luò)環(huán)境下,不經(jīng)優(yōu)化https
的體驗(yàn)確實(shí)會(huì)明顯不如http
捶码。在不具備https
條件或?qū)W(wǎng)絡(luò)性能要求較高且缺乏https
優(yōu)化經(jīng)驗(yàn)的場(chǎng)景下羽氮,http
的流量也應(yīng)該使用 AES 進(jìn)行加密。AES 的密鑰可以由客戶端來(lái)臨時(shí)生成惫恼,不過(guò)這個(gè)臨時(shí)的 AESkey 需要使用服務(wù)器的公鑰進(jìn)行加密档押,確保只有自己的服務(wù)器才能解開這個(gè)請(qǐng)求的信息,當(dāng)然服務(wù)器的response
也需要使用同樣的 AESkey 進(jìn)行加密祈纯。由于http
的應(yīng)用場(chǎng)景都是由客戶端發(fā)起令宿,服務(wù)器響應(yīng),所以這種由客戶端單方生成密鑰的方式可以一定程度上便捷的保證通信安全腕窥。 - AES 使用 CBC 模式:
不要使用 ECB 模式粒没,記得設(shè)置初始化向量,每個(gè)block
加密之前要和上個(gè)block
的密文進(jìn)行運(yùn)算簇爆。
main() 之前的過(guò)程有哪些癞松?
-
dyld
開始將程序二進(jìn)制文件初始化 - 交由
ImageLoader
讀取image
,其中包含了我們的類入蛆,方法等各種符號(hào)(Class响蓉、Protocol 、Selector哨毁、 IMP) - 由于
runtime
向dyld
綁定了回調(diào)枫甲,當(dāng)image
加載到內(nèi)存后,dyld
會(huì)通知runtime
進(jìn)行處理 -
runtime
接手后調(diào)用map_images
做解析和處理 - 接下來(lái)
load_images
中調(diào)用call_load_methods
方法挑庶,遍歷所有加載進(jìn)來(lái)的Class
言秸,按繼承層次依次調(diào)用Class
的+load
和其他Category
的+ load
方法 - 至此 所有的信息都被加載到內(nèi)存中
- 最后
dyld
調(diào)用真正的main
函數(shù) -
dyld
會(huì)緩存上一次把信息加載內(nèi)存的緩存软能,所以第二次比第一次啟動(dòng)快
為什么說(shuō) Objective-C 是一門動(dòng)態(tài)的語(yǔ)言?
- Objective-C 是 C 語(yǔ)言的一個(gè)子類迎捺,所以 Objective-C 是一個(gè)靜態(tài)語(yǔ)言,但 Objective-C 的三大特性之一的多態(tài)讓其擁有了動(dòng)態(tài)性查排。
- Objective-C 的動(dòng)態(tài)性凳枝,讓程序在運(yùn)行時(shí)判斷其該有的行為,而不是像 C 等靜態(tài)語(yǔ)言在編譯構(gòu)建時(shí)就確定下來(lái)。它的動(dòng)態(tài)性主要體現(xiàn)在 3 個(gè)方面:
1.動(dòng)態(tài)類型:如id
類型岖瑰。實(shí)際上靜態(tài)類型因?yàn)槠涔潭ㄐ院涂深A(yù)知性而使用的特別廣泛叛买。靜態(tài)類型是強(qiáng)類型,動(dòng)態(tài)類型是弱類型蹋订,運(yùn)行時(shí)決定接收者率挣。
2.動(dòng)態(tài)綁定:讓代碼在運(yùn)行時(shí)判斷需要調(diào)用什么方法,而不是在編譯時(shí)露戒。與其他面向?qū)ο笳Z(yǔ)言一樣椒功,方法調(diào)用和代碼并沒(méi)有在編譯時(shí)連接在一起,而是在消息發(fā)送時(shí)才進(jìn)行連接智什。運(yùn)行時(shí)決定調(diào)用哪個(gè)方法动漾。
3.動(dòng)態(tài)載入。讓程序在運(yùn)行時(shí)添加代碼模塊以及其他資源荠锭。用戶可以根據(jù)需要執(zhí)行一些可執(zhí)行代碼和資源旱眯,而不是在啟動(dòng)時(shí)就加載所有組件≈ぞ牛可執(zhí)行代碼中可以含有和程序運(yùn)行時(shí)整合的新類删豺。
MVC 和 MVVM,MVP 愧怜?
MVC
-
view
傳送指令到controller
-
controller
完成業(yè)務(wù)邏輯后吼鳞,要求model
改變狀態(tài) -
model
將新的數(shù)據(jù)發(fā)送到view
,用戶得到反饋 - 所有通信都是單向的
MVP
- 將
controller
改名為presenter
叫搁,同時(shí)改變了通信方向 - 各部分之間的通信赔桌,都是雙向的
-
view
與model
不發(fā)生聯(lián)系,都通過(guò)presenter
傳遞 -
view
不部署任何業(yè)務(wù)邏輯渴逻,稱為"被動(dòng)視圖"(Passive View)疾党,即沒(méi)有任何主動(dòng)性,而presenter
部署所有邏輯
MVVM
- 將
presenter
改名為viewModel
惨奕,基本上與 MVP 模式完全一致 - MVVM 采用雙向綁定(data-binding):
view
的變動(dòng)雪位,自動(dòng)反映在viewModel
,反之亦然
為什么代理要用 weak梨撞?代理的 delegate 和 dataSource 有什么區(qū)別雹洗? block 和代理的區(qū)別?
- 代理使用
weak
來(lái)修飾:
1.為了避免循環(huán)引用卧波。
2.當(dāng)對(duì)象釋放的時(shí)候时肿,系統(tǒng)會(huì)對(duì)屬性賦值nil
,Objective-C 有個(gè)特性就是對(duì)nil
對(duì)象發(fā)送消息也就是調(diào)用方法港粱,不會(huì)cash
螃成。 - delegate:傳遞的是事件(even)
- dataSource:傳遞的是數(shù)據(jù)
- block 和代理的區(qū)別
1.代理更面向過(guò)程旦签,block
更面向結(jié)果
屬性的實(shí)質(zhì)是什么?包括哪幾個(gè)部分寸宏?屬性默認(rèn)的關(guān)鍵字都有哪些宁炫?@dynamic 關(guān)鍵字和 @synthesize 關(guān)鍵字是用來(lái)做什么的?
@property = ivar + getter + setter
- 基本數(shù)據(jù)
atomic, readwrite, assign
- 對(duì)象
atomic, readwrite, strong
- @dynamic 修飾的屬性氮凝,其
getter
和setter
方法編譯器是不會(huì)自動(dòng)幫你生成羔巢,必須自己是實(shí)現(xiàn)的。 - @synthesize 修飾的屬性罩阵,其
getter
和setter
方法編譯器是會(huì)自動(dòng)幫你生成朵纷,不必自己實(shí)現(xiàn),且指定與屬性相對(duì)應(yīng)的成員變量永脓。
atomic 安全么袍辞?
- atomic 原子操作,所謂原子常摧,就是不可再化分搅吁,已經(jīng)是最小的操作單位(所謂操作指的是對(duì)內(nèi)存的讀寫)
- 一個(gè)數(shù)據(jù)的線程安全,簡(jiǎn)單點(diǎn)來(lái)說(shuō)就是這塊數(shù)據(jù)即使有多個(gè)線程同時(shí)讀寫落午,也不會(huì)出現(xiàn)數(shù)據(jù)的錯(cuò)亂谎懦,內(nèi)存的最后狀態(tài)是可預(yù)見(jiàn)的
- 在 64 位的操作系統(tǒng)下,所有類型的指針溃斋,包括
void *
都是占用 8 個(gè)字節(jié)界拦,以 Objective-C 下的NSArray *
為例子,如果一個(gè)多線程操作這個(gè)數(shù)據(jù)梗劫,會(huì)有兩個(gè)層級(jí)的并發(fā)問(wèn)題享甸,1、指針本身梳侨。2蛉威、指針?biāo)赶虻膬?nèi)存,所以這個(gè)數(shù)據(jù)array
多線程操作的時(shí)候走哺,必須分成兩部分來(lái)描述蚯嫌,一個(gè)是&array
這個(gè)指針本身,另一個(gè)則是它所指向的內(nèi)存array
-
@property(atomic)NSArray *array
其實(shí)修飾的是這個(gè)指針丙躏,也就是這個(gè) 8 字節(jié)內(nèi)存择示,跟第二部分?jǐn)?shù)據(jù) n 字節(jié)沒(méi)有任何關(guān)系,被atomic
修飾之后晒旅,你不可能隨意去多線程操作這個(gè) 8 字節(jié)栅盲,但是對(duì) 8 字節(jié)里面所指向的 n 字節(jié)沒(méi)有任何限制 - atomic 只對(duì)
get
和set
方法起作用:我們知道,這個(gè) 8 字節(jié)里面存儲(chǔ)的數(shù)據(jù)敢朱,是 n 字節(jié)數(shù)據(jù)的頭地址剪菱,如果更改 8 字節(jié)數(shù)據(jù)的內(nèi)容摩瞎,那么最后通過(guò)這個(gè)指針訪問(wèn)到的數(shù)據(jù)就會(huì)完全不一樣
如何令自己所寫的對(duì)象具有拷貝功能?
- 遵循
NSCopying
協(xié)議拴签,并且實(shí)現(xiàn)- (id)copyWithZone:(NSZone *)zone
方法 - 如果讓自己的類具備
mutableCopy
方法孝常,必須遵守NSMutableCopying
,并實(shí)現(xiàn)- (id)mutableCopyWithZone:(nullable NSZone *)zone
方法
進(jìn)程和線程的區(qū)別蚓哩?同步異步的區(qū)別构灸?并行和并發(fā)的區(qū)別?
進(jìn)程和線程的區(qū)別
- 進(jìn)程是資源的分配和調(diào)度的一個(gè)獨(dú)立單元岸梨,而線程是 CPU 調(diào)度的基本單元
- 同一個(gè)進(jìn)程中可以包括多個(gè)線程喜颁,并且線程共享整個(gè)進(jìn)程的資源(寄存器、堆棧曹阔、上下文)半开,一個(gè)進(jìn)程至少包括一個(gè)線程。
- 進(jìn)程的創(chuàng)建調(diào)用
fork
或者vfork
赃份,而線程的創(chuàng)建調(diào)用pthread_create
寂拆,進(jìn)程結(jié)束后它擁有的所有線程都將銷毀,而線程的結(jié)束不會(huì)影響同個(gè)進(jìn)程中的其他線程的結(jié)束 - 線程是輕兩級(jí)的進(jìn)程抓韩,它的創(chuàng)建和銷毀所需要的時(shí)間比進(jìn)程小很多纠永,所有操作系統(tǒng)中的執(zhí)行功能都是創(chuàng)建線程去完成的
- 線程中執(zhí)行時(shí)一般都要進(jìn)行同步和互斥,因?yàn)樗麄児蚕硗贿M(jìn)程的所有資源
- 線程有自己的私有屬性 TCB谒拴,線程
id
尝江,寄存器、硬件上下文英上,而進(jìn)程也有自己的私有屬性進(jìn)程控制塊 PCB炭序,這些私有屬性是不被共享的,用來(lái)標(biāo)示一個(gè)進(jìn)程或一個(gè)線程的標(biāo)志
同步和異步的區(qū)別
- 同步(synchronous):進(jìn)程之間的關(guān)系不是相互排斥臨界資源的關(guān)系苍日,而是相互依賴的關(guān)系少态。進(jìn)一步的說(shuō)明:就是前一個(gè)進(jìn)程的輸出作為后一個(gè)進(jìn)程的輸入,當(dāng)?shù)谝粋€(gè)進(jìn)程沒(méi)有輸出時(shí)第二個(gè)進(jìn)程必須等待易遣。具有同步關(guān)系的一組并發(fā)進(jìn)程相互發(fā)送的信息稱為消息或事件
- 異步(asynchronous):異步和同步是相對(duì)的彼妻,同步就是順序執(zhí)行,執(zhí)行完一個(gè)再執(zhí)行下一個(gè)豆茫,需要等待侨歉、協(xié)調(diào)運(yùn)行。異步就是彼此獨(dú)立,在等待某事件的過(guò)程中繼續(xù)做自己的事揩魂,不需要等待這一事件完成后再工作幽邓。線程就是實(shí)現(xiàn)異步的一個(gè)方式。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成火脉,從而可以讓主線程干其它的事情
并行和并發(fā)的區(qū)別
- 并發(fā):在操作系統(tǒng)中牵舵,是指一個(gè)時(shí)間段中有幾個(gè)程序都處于已啟動(dòng)運(yùn)行到運(yùn)行完畢之間柒啤,且這個(gè)幾個(gè)程序都是在同一個(gè)處理機(jī)上運(yùn)行。其中兩種并發(fā)關(guān)系分別是同步和互斥畸颅。
互斥:進(jìn)程間相互排斥的使用臨界資源的現(xiàn)象
同步:進(jìn)程之間的關(guān)系不是相互排斥臨界資源的關(guān)系担巩,而是相互依賴的關(guān)系。進(jìn)一步說(shuō)明就是前一個(gè)進(jìn)程的輸出作為后一個(gè)進(jìn)程的輸入没炒,當(dāng)?shù)谝粋€(gè)進(jìn)程沒(méi)有輸出時(shí)第二個(gè)進(jìn)程必須等待涛癌。具有同步關(guān)系的一組并發(fā)進(jìn)程相互發(fā)送的信息稱為消息或事件。
其中并發(fā)又有偽并發(fā)和真并發(fā)送火,偽并發(fā)是指單核處理器的并發(fā)拳话,真并發(fā)是指多核處理器的并發(fā)。 - 并行(parallelism):在單處理器中多道程序設(shè)計(jì)系統(tǒng)中种吸,進(jìn)程被交替執(zhí)行弃衍,表現(xiàn)出一種并發(fā)的外部特種;在多處理器系統(tǒng)中坚俗,進(jìn)程不僅可以交替執(zhí)行镜盯,而且可以重疊執(zhí)行。在多處理器上的程序才可實(shí)現(xiàn)并行處理坦冠。從而可知形耗,并行是針對(duì)多處理器而言的。并行是同時(shí)發(fā)生的多個(gè)并發(fā)事件辙浑,具有并發(fā)的含義辕漂,但并發(fā)不一定并行血淌,也亦是說(shuō)并發(fā)事件之間不一定要同一時(shí)刻發(fā)生兼耀。
Designated Initializer ?
- 指定初始化函數(shù)對(duì)一個(gè)類來(lái)說(shuō)非常重要磁浇,通常參數(shù)也是最多的,試想每次我們需要?jiǎng)?chuàng)建一個(gè)自定義類都需要一堆參數(shù)侠草,那豈不是很痛苦辱挥。便利初始化函數(shù)就是用來(lái)幫我們解決這個(gè)問(wèn)題的,可以讓我們比較的創(chuàng)建對(duì)象边涕,同時(shí)又可以保證類的成員變量被設(shè)置為默認(rèn)的值晤碘。
- 子類如果有指定初始化函數(shù),那么指定初始化函數(shù)實(shí)現(xiàn)時(shí)必須調(diào)用它的直接父類的指定初始化函數(shù)
- 如果子類有指定初始化函數(shù)功蜓,那么便利初始化函數(shù)必須調(diào)用自己的其它初始化函數(shù)(包括指定初始化函數(shù)以及其他的便利初始化函數(shù))园爷,不能調(diào)用
super
的初始化函數(shù)
能否向編譯后得到的類中增加實(shí)例變量?能否向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量式撼?
- 不能向編譯后得到的類增加實(shí)例變量,編譯后的類已經(jīng)注冊(cè)在
runtime
中,類結(jié)構(gòu)體中的objc_ivar_list
實(shí)例變量的鏈表和instance_size
實(shí)例變量的內(nèi)存大小已經(jīng)確定童社,runtime
會(huì)調(diào)用class_setvarlayout
或class_setWeaklvarLayout
來(lái)處理strong weak
引用,所以不能向存在的類中添加實(shí)例變量 - 能向運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量著隆,運(yùn)行時(shí)創(chuàng)建的類是可以添加實(shí)例變量,調(diào)用
class_addIvar
函數(shù)扰楼。但是需要在調(diào)用objc_allocateClassPair
之后呀癣,objc_registerClassPair
之前,原因同上
給類添加一個(gè)屬性后弦赖,在類結(jié)構(gòu)體里哪些元素會(huì)發(fā)生變化项栏?
- instance_size: 實(shí)例的內(nèi)存大小
- objc_ivar_list *ivars: 屬性列表
runloop 的 mode 是用來(lái)做什么的?有幾種 mode腾节?
- model 是
runloop
里面的模式忘嫉,不同的模式下的runloop
處理的事件和消息有一定的差別,系統(tǒng)默認(rèn)注冊(cè)了 5 個(gè) model 荤牍。 - kCFRunLoopDefaultMode: App 的默認(rèn) Mode案腺,通常主線程是在這個(gè) Mode 下運(yùn)行的。
- UITrackingRunLoopMode: 界面跟蹤 Mode康吵,用于
ScrollView
追蹤觸摸滑動(dòng)劈榨,保證界面滑動(dòng)時(shí)不受其他 Mode 影響。 - UIInitializationRunLoopMode: 在剛啟動(dòng) App 時(shí)第進(jìn)入的第一個(gè) Mode晦嵌,啟動(dòng)完成后就不再使用同辣。
- GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到惭载。
- kCFRunLoopCommonModes: 這是一個(gè)占位的 Mode旱函,沒(méi)有實(shí)際作用。
- 5 種 model 進(jìn)行了封裝
NSDefaultRunLoopMode
NSRunLoopCommonModes
- NStime 對(duì)象默認(rèn)是在
NSDefaultRunLoopMode
下面調(diào)用消息的描滔,但是當(dāng)我們滑動(dòng)scrollview
的時(shí)候棒妨,NSDefaultRunLoopMode
模式就自動(dòng)切換到UITrackingRunLoopMode
模式下面
isa 指針?
- 對(duì)象的
isa
指針指向所屬的類 - 類的
isa
指針指向了所屬的元類(metaclass) - 元類的
isa
指向了根元類(root metaclass)含长,根元類本身的isa
指針指向自己券腔,這樣就形成了一個(gè)閉環(huán)
Objective-C 中向一個(gè) nil 對(duì)象發(fā)送消息將會(huì)發(fā)生什么?
- Objective-C 中向
nil
發(fā)送消息是完全有效的拘泞,只是在運(yùn)行時(shí)不會(huì)有任何作用纷纫。 - 如果一個(gè)方法返回值是一個(gè)對(duì)象,那么發(fā)送給
nil
的消息將返回 0 (nil)陪腌。 - 如果方法返回值為指針類型辱魁,其指針大小為小于或者等于
sizeof(void*),float诗鸭,double染簇,long double
或者long long
的整型標(biāo)量,發(fā)送給nil
的消息將返回 0只泼。 - 如果方法返回值為結(jié)構(gòu)體剖笙,發(fā)送給
nil
的消息將返回 0。結(jié)構(gòu)體中各個(gè)字段的值將都是 0请唱。其他的結(jié)構(gòu)體數(shù)據(jù)類型將不是用 0 填充的弥咪。 - 如果方法的返回值不是上述提到的幾種情況过蹂,那么發(fā)送給nil的消息的返回值將是未定義的。
.a 與 .framework 庫(kù)的區(qū)別聚至?靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)的區(qū)別酷勺?
- .a 是一個(gè)純二進(jìn)制文件,不能直接使用扳躬,至少要有 .h 文件配合脆诉。
- .framework 中除了有二進(jìn)制文件之外還有資源文件,可以直接使用贷币。
- 靜態(tài)庫(kù):以 .a 和 .framework 為文件后綴名击胜,鏈接時(shí)會(huì)被完整的復(fù)制到可執(zhí)行文件中,被多次使用就有多份拷貝役纹。
- 動(dòng)態(tài)庫(kù):以
.tbd
(之前叫.dylib
) 和 .framework 為文件后綴名偶摔,鏈接時(shí)不復(fù)制,程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)加載到內(nèi)存促脉,系統(tǒng)只加載一次辰斋,多個(gè)程序共用(如系統(tǒng)的UIKit.framework
等),節(jié)省內(nèi)存瘸味。 - Apple 不讓使用自己的動(dòng)態(tài)庫(kù)宫仗,iOS8 之后雖然可以上傳含有動(dòng)態(tài)庫(kù)的 App,但是 Apple 不僅需要你動(dòng)態(tài)庫(kù)和 App 的簽名一致旁仿,而且蘋果會(huì)在你上架的時(shí)候再經(jīng)過(guò)一次 AppStore 的簽名藕夫。
如何讓靜態(tài)庫(kù)中的 Category 變得可用?
- Objective-C 不會(huì)為方法定義
linker symbols
丁逝,它只會(huì)為每一個(gè)類定義linker symbols
汁胆。如果你使用category
擴(kuò)展了一個(gè)已經(jīng)存在的類,那么linke
r 不會(huì)將已有類的實(shí)現(xiàn)跟category
的實(shí)現(xiàn)連接起來(lái)霜幼,這就導(dǎo)致了調(diào)用靜態(tài)庫(kù)中category
中新增加的方法時(shí)拋出selector not recognized
的異常嫩码。 - 通過(guò)在
Other Linker Flags
添加-all_load
,它會(huì)告訴編譯器“對(duì)于所有文檔中的所有對(duì)象文件罪既,不管里面的符號(hào)有沒(méi)有被用到铸题,都載入”,這種方法確實(shí)可以琢感,但是會(huì)產(chǎn)生比較大的二進(jìn)制文件丢间。 - 添加
-force_load
和指定的路徑,這種方法和-all_load
很像驹针,不同的是它只使用指定的歸檔烘挫。 - 在
Other Linker Flags
中添加-ObjC
,這個(gè)標(biāo)識(shí)告訴編譯器“如果你在文檔里的對(duì)象文件中發(fā)現(xiàn)了 Objective-C 代碼,就把它載入“饮六,Category 里當(dāng)然也有 Objective-C 代碼其垄。使用這種方法不會(huì)載入任何沒(méi)有 Objective-C 代碼的文件 - 啟用 Xcode 里 build setting 中的
PerformSingle-Object PreLink
,所有的對(duì)象文件都會(huì)被合并成一個(gè)單文件(這不是真正的鏈接卤橄,所以叫做預(yù)鏈接)绿满,這個(gè)對(duì)象文件(有時(shí)被稱做主對(duì)象文件(masterobject file)被添加到文檔中。現(xiàn)在如果主對(duì)象文件中的任何符號(hào)被認(rèn)為是“在使用”窟扑,整個(gè)主對(duì)象文件都會(huì)被認(rèn)為在使用喇颁,這樣它里面的 Objective-C 部分就會(huì)被載入了。因?yàn)槔锩娴念惗急徽7?hào)化了嚎货,所以能使從這樣的靜態(tài)庫(kù)中使用所有的category
橘霎。 - 在只有
category
的源文件里添加Fakesymbol
。如果你想在runtime
里使用category
厂抖,一定要確保你以某種方法在編譯時(shí)引用了fake symbol
茎毁,這會(huì)使得對(duì)象文件以及它里面的 Objective-C 代碼被載入克懊。和上面其他的解決方法不一樣忱辅,這種解決方法可以控制哪些category
可以在runtime
里被編譯后的代碼使用(可以通過(guò)使用這個(gè)符號(hào),使它們被鏈接并變得可用谭溉;也可以不使用這個(gè)符號(hào)墙懂,這樣鏈接器就會(huì)忽略它)。
BitCode 的理解扮念。
- Bitcode 是被編譯程序的一種中間形式的代碼损搬。包含 Bitcode 配置的程序?qū)?huì)在 App store 上被編譯(可執(zhí)行的 64 位或 32 位程序)和鏈接。
- Bitcode柜与,做的事情是指令集優(yōu)化巧勤,根據(jù)你設(shè)備的狀態(tài)去做編譯優(yōu)化,進(jìn)而提升性能弄匕,對(duì)包的大小優(yōu)化起不到什么本質(zhì)上的作用颅悉。
- APP Thining 是由 App Slicing、On Demand Resources和 Bitcode 組成迁匠。
- App Slicing:根據(jù)你設(shè)備型號(hào)剩瓶,生成對(duì)應(yīng)資源的 ipa,以節(jié)省空間城丧。
- On Demand Resources:按需加載資源
WKWebView 和 UIWebView 的區(qū)別延曙?無(wú)痕瀏覽的實(shí)現(xiàn)。
- 在性能亡哄、穩(wěn)定性枝缔、功能方面有很大提升,直觀體現(xiàn)是內(nèi)存占用變少蚊惯。
- 允許
JavaScript
的Nitro
庫(kù)加載并使用(UIWebView
中限制)愿卸。 - 支持了更多的
HTML5
特性拐辽。 - 高達(dá)
60fps
的滾動(dòng)刷新率以及內(nèi)置手勢(shì)。 - 將
UIWebViewDelegate
與UIWebView
重構(gòu)成了14類與3個(gè)協(xié)議(詳見(jiàn)官方文檔)擦酌。 - WKWebView的
Cookie
存儲(chǔ)在WKWebsiteDataStore
中俱诸。WKWebsiteDataStore
中存儲(chǔ)了包括cookies、disk赊舶、memory caches睁搭、WebSQL、IndexedDB
數(shù)據(jù)庫(kù)和本地存儲(chǔ)等web
內(nèi)容笼平。
//defaultDataStore 是默認(rèn)選擇的存儲(chǔ)容器
+ (WKWebsiteDataStore *)defaultDataStore;
//nonPersistentDataStore 會(huì)禁止任何數(shù)據(jù)寫入文件系統(tǒng)园骆,可用于無(wú)痕瀏覽
+ (WKWebsiteDataStore *)nonPersistentDataStore;
//可以查看到容器中存儲(chǔ)的網(wǎng)站數(shù)據(jù)的所有種類
+ (NSSet<NSString *> *)allWebsiteDataTypes;
//獲取容器中的數(shù)據(jù)記錄
- (void)fetchDataRecordsOfTypes:(NSSet<NSString *> *)dataTypes completionHandler:(void (^)(NSArray<WKWebsiteDataRecord *> *))completionHandler;
//刪除容器中的數(shù)據(jù)記錄
- (void)removeDataOfTypes:(NSSet<NSString *> *)dataTypes forDataRecords:(NSArray<WKWebsiteDataRecord *> *)dataRecords completionHandler:(void (^)(void))completionHandler;
- (void)removeDataOfTypes:(NSSet<NSString *> *)websiteDataTypes modifiedSince:(NSDate *)date completionHandler:(void (^)(void))completionHandler;
NSURLSession 和 NSURLConnection 的區(qū)別?
-
NSURLConnection
是 iOS2.0 后推出的寓调,NSURLSession
是 iOS7.0 后推出的,用于代替NSURLConnection
锌唾。 - 下載任務(wù)方式:
NSURLConnection
下載文件時(shí),先是將整個(gè)文件下載到內(nèi)存夺英,然后再寫入到沙盒晌涕,如果文件比較大,就會(huì)出現(xiàn)內(nèi)存暴漲的情況痛悯。而使用NSURLSessionUploadTask
下載文件余黎,會(huì)默認(rèn)下載到沙盒中的tem
文件中,不會(huì)出現(xiàn)內(nèi)存暴漲的情況载萌,但是在下載完成后會(huì)把tem
中的臨時(shí)文件刪除惧财,需要在初始化任務(wù)方法時(shí),在completionHandler
回調(diào)中增加保存文件的代碼扭仁。 - 請(qǐng)求方式的控制:
NSURLConnection
實(shí)例化對(duì)象垮衷,實(shí)例化開始,默認(rèn)請(qǐng)求就發(fā)送(同步發(fā)送),不需要調(diào)用start
方法乖坠。而cancel
可以停止請(qǐng)求的發(fā)送搀突,停止后不能繼續(xù)訪問(wèn),需要?jiǎng)?chuàng)建新的請(qǐng)求瓤帚。NSURLSession
有三個(gè)控制方法描姚,取消(cancel)、暫停(suspend)戈次、繼續(xù)(resume)轩勘,暫停以后可以通過(guò)繼續(xù)恢復(fù)當(dāng)前的請(qǐng)求任務(wù)。 - 斷點(diǎn)續(xù)傳實(shí)現(xiàn)方式 :·NSURLConnection· 進(jìn)行斷點(diǎn)下載怯邪,通過(guò)設(shè)置訪問(wèn)請(qǐng)求的
HTTPHeaderField
的Range
屬性绊寻,開啟運(yùn)行循環(huán),NSURLConnection
的代理方法作為運(yùn)行循環(huán)的事件源,接收到下載數(shù)據(jù)時(shí)代理方法就會(huì)持續(xù)調(diào)用澄步,并使用NSOutputStream
管道流進(jìn)行數(shù)據(jù)保存冰蘑。NSURLSession
進(jìn)行斷點(diǎn)下載,當(dāng)暫停下載任務(wù)后村缸,如果downloadTask
(下載任務(wù))為非空祠肥,調(diào)用cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler
這個(gè)方法,這個(gè)方法接收一個(gè)參數(shù)梯皿,完成處理代碼塊仇箱,這個(gè)代碼塊有一個(gè)NSData
參數(shù)resumeData
,如果resumeData
非空东羹,我們就保存這個(gè)對(duì)象到視圖控制器的resumeData
屬性中剂桥,在點(diǎn)擊再次下載時(shí),通過(guò)調(diào)用[ [self.session downloadTaskWithResumeData:self.resumeData] resume]
方法進(jìn)行繼續(xù)下載操作属提,使用NSURLSession
進(jìn)行斷點(diǎn)下載更加便捷. - 配置信息:
NSURLSession
的構(gòu)造方法(sessionWithConfiguration:delegate:delegateQueue)
中有一個(gè)NSURLSessionConfiguration
類的參數(shù)可以設(shè)置配置信息权逗,其決定了cookie
,安全和高速緩存策略冤议,最大主機(jī)連接數(shù)斟薇,資源管理,網(wǎng)絡(luò)超時(shí)等配置求类。NSURLConnection
不能進(jìn)行這個(gè)配置奔垦,相比較與NSURLConnection
依賴與一個(gè)全局的配置對(duì)象,缺乏靈活性而言尸疆,NSURLSession
有很大改進(jìn)。 -
NSURLSession
支持HTTP 2.0
WKWebView 支持 NSURLProtocol 嗎
-
WKWebView
是支持NSURLProtocol
攔截的惶岭,只是WebKit.framework
還不完善寿弱。
WebKit 源碼由三大部分組成:
- WebCore:
HTML
排版引擎核心,主要包含Loader按灶,Parser(DOM症革,Render),Layout鸯旁,Paint
等模塊 - WebKit:移植層噪矛,主要包括
GUI,F(xiàn)ile System铺罢,Thread
艇挨,圖片解碼等與平臺(tái)相關(guān)的模塊 - JavaScriptCore:
JS
虛擬機(jī),主要用于操作DOM
韭赘,解析執(zhí)行JavaScript
代碼
- WKWebView:網(wǎng)頁(yè)的渲染與展示缩滨,通過(guò)
WKWebViewConfiguration
可以進(jìn)行配置。 - WKWebViewConfiguration:這個(gè)類專門用來(lái)配置
WKWebView
。 - WKPreference:這個(gè)類用來(lái)進(jìn)行相關(guān)設(shè)置脉漏。
- WKProcessPool:這個(gè)類用來(lái)配置進(jìn)程池苞冯,與網(wǎng)頁(yè)視圖的資源共享有關(guān)。
- WKUserContentController:這個(gè)類主要用來(lái)做
native
與JavaScript
的交互管理侧巨。 - WKUserScript:用于進(jìn)行
JavaScript
注入舅锄。 - WKScriptMessageHandler:這個(gè)類專門用來(lái)處理
JavaScript
調(diào)用native
的方法。 - WKNavigationDelegate:網(wǎng)頁(yè)跳轉(zhuǎn)間的導(dǎo)航管理協(xié)議司忱,這個(gè)協(xié)議可以監(jiān)聽網(wǎng)頁(yè)的活動(dòng)巧娱。
- WKNavigationAction:網(wǎng)頁(yè)某個(gè)活動(dòng)的示例化對(duì)象。
- WKUIDelegate:用于交互處理
JavaScript
中的一些彈出框烘贴。 - WKBackForwardList:堆棧管理的網(wǎng)頁(yè)列表禁添。
- WKBackForwardListItem:每個(gè)網(wǎng)頁(yè)節(jié)點(diǎn)對(duì)象。
WKWebView 在 WebKit 中的初始化流程:
- 根據(jù)配置項(xiàng)
WKWebViewConfiguration
創(chuàng)建新WKWebView
桨踪,同時(shí)會(huì)初始化WKScrollView
和WKContentView
老翘; -
WKContentView
從進(jìn)程池WKProcessPool
中分配WebProcessProxy
和WebPageProxy
,同時(shí)根據(jù)當(dāng)前Page
初始化WKBrowsingContextController
锻离,提供了大部分交互操作功能铺峭; -
WKWebView
在獨(dú)立于App Process
進(jìn)程之外的Network Process
進(jìn)程中執(zhí)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求數(shù)據(jù)不經(jīng)過(guò)主進(jìn)程汽纠,因此卫键,在WKWebView
上直接使用NSURLProtocol
無(wú)法攔截請(qǐng)求。
一個(gè)完整的網(wǎng)絡(luò)請(qǐng)求代理攔截處理流程:
-
WKBrowsingContextController
通過(guò)registerSchemeForCustomProtocol
向WebProcessPool
注冊(cè)全局自定義scheme
-
WebProcessPool
使用已注冊(cè)的scheme
初始化Network Process
進(jìn)程配置虱朵,同時(shí)設(shè)置CustomProtocolManager
莉炉,負(fù)責(zé)把網(wǎng)絡(luò)請(qǐng)求通過(guò) IPC 發(fā)送到App Process
進(jìn)程、也接收從App Process
進(jìn)程返回的網(wǎng)絡(luò)響應(yīng)response
-
CustomProtocolManager
注冊(cè)了NSURLProtocol
的子類WKCustomProtocol
碴犬,負(fù)責(zé)攔截網(wǎng)絡(luò)請(qǐng)求處理 -
CustomProtocolManagerProxy
中的WKCustomProtocolLoader
使用NSURLConnection
發(fā)送實(shí)際的網(wǎng)絡(luò)請(qǐng)求絮宁,并將響應(yīng)response
返回給CustomProtocolManager
- 詳見(jiàn)NSURLProtocol-WebKitSupport
__weak & __unsafe_unretained 的區(qū)別
- __unsafe_unretained: 不會(huì)對(duì)對(duì)象進(jìn)行
retain
,當(dāng)對(duì)象銷毀時(shí)服协,依然會(huì)指向之前的內(nèi)存空間(野指針)绍昂。 - __weak:不會(huì)對(duì)對(duì)象進(jìn)行
retain
,當(dāng)對(duì)象銷毀時(shí)偿荷,會(huì)自動(dòng)置為nil
窘游。
NSCatch 和 NSDictionary區(qū)別?
-
NSCache
在系統(tǒng)內(nèi)存很低時(shí)會(huì)自動(dòng)釋放對(duì)象。 -
NSCache
是線程安全的跳纳,在進(jìn)行多線程操作時(shí)忍饰,不需要進(jìn)行加鎖。 -
NSCatch
可以給對(duì)象設(shè)置上限棒旗,用以限制緩存中的對(duì)象總個(gè)數(shù)喘批。 -
NSCache
不會(huì)拷貝Key
撩荣。
實(shí)例方法與類方法的區(qū)別
實(shí)例方法
- 減號(hào) - 開頭。
- 只能由對(duì)象來(lái)調(diào)用饶深。
- 對(duì)象方法中能訪問(wèn)當(dāng)前對(duì)象的成員變量(實(shí)例變量)餐曹。
-
self
是對(duì)象的首地址。
類方法
- 加號(hào) + 開頭敌厘。
- 只能由類(名)來(lái)調(diào)用台猴。
- 類方法中不能訪問(wèn)成員變量(實(shí)例變量)。
-
self
是Class
俱两。