KVO 實現(xiàn)原理?
- 利用
Runtime動態(tài)生成一個子類,并且讓instance對象的isa指向這個全新的子類 - 當修改
instance對象的屬性時,會調(diào)用Foundation框架的_NSSetXXXValueAndNotify函數(shù) ,該函數(shù)里面會先調(diào)用willChangeValueForKey:然后調(diào)用父類原來的setter方法修改值,最后是didChangeValueForKey:。didChangeValueForKey 內(nèi)部會觸發(fā)監(jiān)聽器(Oberser)的監(jiān)聽方法observeValueForKeyPath:ofObject:change:context: - 如果需要手動觸發(fā)
KVO,只需要手動調(diào)用willChangeValueForKey:和didChangeValueForKey:兩個方法即可。
KVC 實現(xiàn)原理?
setValue:forKey
- 按照
setKey:, _setKey:順序查找方法 ,找到了就傳遞參數(shù),調(diào)用方法。 - 如果沒有找到,就查看
accessInstanceVariablesDirectly方法(默認為 YES)的返回值。 - 如果返回值是 YES,那么按
_key,_isKey,key,iskey的順序查找成員變量,找到了直接賦值,找不到就調(diào)用setValue:forUnderfinedKey:方法并拋出異常NSUnknownKeyException。 - 如果返回值是 NO,就調(diào)用
setValue:forUnderfinedKey:方法并拋出異常 NSUnknownKeyException。
valueForKey
- 按照
getKey,key,isKey, _key的順序查找方法,找到直接調(diào)用。 - 如果沒有找到,就查看
accessInstanceVariablesDirectly方法(默認為 YES)的返回值。 - 如果返回值是 YES,那么按
_key,_isKey,key,iskey的順序查找成員變量,找到了直接取值,找不到就調(diào)用setValue:forUnderfinedKey:方法并拋出異常NSUnknownKeyException。 - 如果返回值是 NO,就調(diào)用
setValue:forUnderfinedKey:方法并拋出異常 NSUnknownKeyException。
消息轉(zhuǎn)發(fā)機制原理?
- 動態(tài)方法解析:
對象在接收到未知的消息時,首先會調(diào)用所屬類的類方法+resolveInstanceMethod:或者+resolveClassMethod:。在這個方法中,我們有機會為該未知消息新增一個”處理方法”“。不過使用該方法的前提是我們已經(jīng)實現(xiàn)了該”處理方法”,只需要在運行時通過
class_addMethod函數(shù)動態(tài)添加到類里面就可以了。 - 備用接受者:
動態(tài)方法解析無法處理消息,則會走備用接受者。這個備用接受者只能是一個新的對象,不能是self本身,否則就會出現(xiàn)無限循環(huán)。如果我們沒有指定相應的對象來處理selector,則應該調(diào)用父類的實現(xiàn)來返回結果。 - 完整消息轉(zhuǎn)發(fā):
首先創(chuàng)建NSInvocation對象,把尚未處理的消息有關的內(nèi)容封于其中,此對象包括selector、目標(target及參數(shù)。在觸發(fā)NSInvocation對象時,”消息派發(fā)系統(tǒng)“(message-dispatch sys)將會把消息指派給目標對象。若發(fā)現(xiàn)某個操作不應該是本類來處理,就需要調(diào)用父類的同名方法。這樣,繼承體系中的每個類都有機會處理此調(diào)用請求,直至NSObject。如果最后調(diào)用了NSObject的方法,最終該方法就會繼續(xù)調(diào)用doesNotRecognizeSelector:拋出異常,表明 'selector' 未能被處理。
理解 weak 屬性?
-
Runtime維護了一個weak表,用于存儲指向某個對象的所有weak指針。weak表其實是一個hash(哈希)表,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象的地址)數(shù)組。 - 初始化時:
runtime會調(diào)用objc_initWeak函數(shù),初始化一個新的weak指針指向?qū)ο蟮牡刂贰?/li> - 添加引用時:
objc_initWeak函數(shù)會調(diào)用objc_storeWeak()函數(shù),objc_storeWeak()的作用是更新指針指向,創(chuàng)建對應的弱引用表。 - 釋放時,調(diào)用
clearDeallocating函數(shù)。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設為nil,最后從weak表中刪除并清理對象的記錄。
項目中網(wǎng)絡層如何做安全處理?
- 盡量使用
https:
https可以過濾掉大部分的安全問題。https在證書申請,服務器配置,性能優(yōu)化,客戶端配置上都需要投入精力,所以缺乏安全意識的開發(fā)人員容易跳過https,或者拖到以后遇到問題再優(yōu)化。https除了性能優(yōu)化麻煩一些以外其他都比想象中的簡單,如果沒精力優(yōu)化性能,至少在注冊登錄模塊需要啟用https,這部分業(yè)務對性能要求比較低。 - 不要傳輸明文密碼:
不知道現(xiàn)在還有多少 app 后臺是明文存儲密碼的。無論客戶端,server還是網(wǎng)絡傳輸都要避免明文密碼,要使用hash值。客戶端不要做任何密碼相關的存儲,hash值也不行。存儲token進行下一次的認證,而且token需要設置有效期,使用refreshtoken去申請新的token。 -
post并不比get安全:
事實上,post和get一樣不安全,都是明文。參數(shù)放在queryString或者body沒任何安全上的差別。在http的環(huán)境下,使用post或者get都需要做加密和簽名處理。 - 不要使用 301 跳轉(zhuǎn):
301 跳轉(zhuǎn)很容易被http劫持攻擊。移動端http使用 301 比桌面端更危險,用戶看不到瀏覽器地址,無法察覺到被重定向到了其他地址。如果一定要使用,確保跳轉(zhuǎn)發(fā)生在https的環(huán)境下,而且https做了證書綁定校驗。 -
http請求都帶上 MAC:
所有客戶端發(fā)出的請求,無論是查詢還是寫操作,都帶上MAC(Message AuthenticationCode)。MAC 不但能保證請求沒有被篡改(Integrity),還能保證請求確實來自你的合法客戶端(Signing)。當然前提是你客戶端的key沒有被泄漏,如何保證客戶端key的安全是另一個話題。MAC 值的計算可以簡單的處理為hash(request params+key)。帶上 MAC 之后,服務器就可以過濾掉絕大部分的非法請求。MAC 雖然帶有簽名的功能,和 RSA 證書的電子簽名方式卻不一樣,原因是 MAC 簽名和簽名驗證使用的是同一個key,而 RSA 是使用私鑰簽名,公鑰驗證,MAC 的簽名并不具備法律效應。 -
http請求使用臨時密鑰:
高延遲的網(wǎng)絡環(huán)境下,不經(jīng)優(yōu)化https的體驗確實會明顯不如http。在不具備https條件或?qū)W(wǎng)絡性能要求較高且缺乏https優(yōu)化經(jīng)驗的場景下,http的流量也應該使用 AES 進行加密。AES 的密鑰可以由客戶端來臨時生成,不過這個臨時的 AESkey 需要使用服務器的公鑰進行加密,確保只有自己的服務器才能解開這個請求的信息,當然服務器的response也需要使用同樣的 AESkey 進行加密。由于http的應用場景都是由客戶端發(fā)起,服務器響應,所以這種由客戶端單方生成密鑰的方式可以一定程度上便捷的保證通信安全。 - AES 使用 CBC 模式:
不要使用 ECB 模式,記得設置初始化向量,每個block加密之前要和上個block的密文進行運算。
main() 之前的過程有哪些?
-
dyld開始將程序二進制文件初始化 - 交由
ImageLoader讀取image,其中包含了我們的類,方法等各種符號(Class、Protocol 、Selector、 IMP) - 由于
runtime向dyld綁定了回調(diào),當image加載到內(nèi)存后,dyld會通知runtime進行處理 -
runtime接手后調(diào)用map_images做解析和處理 - 接下來
load_images中調(diào)用call_load_methods方法,遍歷所有加載進來的Class,按繼承層次依次調(diào)用Class的+load和其他Category的+ load方法 - 至此 所有的信息都被加載到內(nèi)存中
- 最后
dyld調(diào)用真正的main函數(shù) -
dyld會緩存上一次把信息加載內(nèi)存的緩存,所以第二次比第一次啟動快
為什么說 Objective-C 是一門動態(tài)的語言?
- Objective-C 是 C 語言的一個子類,所以 Objective-C 是一個靜態(tài)語言,但 Objective-C 的三大特性之一的多態(tài)讓其擁有了動態(tài)性。
- Objective-C 的動態(tài)性,讓程序在運行時判斷其該有的行為,而不是像 C 等靜態(tài)語言在編譯構建時就確定下來。它的動態(tài)性主要體現(xiàn)在 3 個方面:
1.動態(tài)類型:如id類型。實際上靜態(tài)類型因為其固定性和可預知性而使用的特別廣泛。靜態(tài)類型是強類型,動態(tài)類型是弱類型,運行時決定接收者。
2.動態(tài)綁定:讓代碼在運行時判斷需要調(diào)用什么方法,而不是在編譯時。與其他面向?qū)ο笳Z言一樣,方法調(diào)用和代碼并沒有在編譯時連接在一起,而是在消息發(fā)送時才進行連接。運行時決定調(diào)用哪個方法。
3.動態(tài)載入。讓程序在運行時添加代碼模塊以及其他資源。用戶可以根據(jù)需要執(zhí)行一些可執(zhí)行代碼和資源,而不是在啟動時就加載所有組件。可執(zhí)行代碼中可以含有和程序運行時整合的新類。
MVC 和 MVVM,MVP ?
MVC

-
view傳送指令到controller -
controller完成業(yè)務邏輯后,要求model改變狀態(tài) -
model將新的數(shù)據(jù)發(fā)送到view,用戶得到反饋 - 所有通信都是單向的
MVP

- 將
controller改名為presenter,同時改變了通信方向 - 各部分之間的通信,都是雙向的
-
view與model不發(fā)生聯(lián)系,都通過presenter傳遞 -
view不部署任何業(yè)務邏輯,稱為"被動視圖"(Passive View),即沒有任何主動性,而presenter部署所有邏輯
MVVM

- 將
presenter改名為viewModel,基本上與 MVP 模式完全一致 - MVVM 采用雙向綁定(data-binding):
view的變動,自動反映在viewModel,反之亦然
為什么代理要用 weak?代理的 delegate 和 dataSource 有什么區(qū)別? block 和代理的區(qū)別?
- 代理使用
weak來修飾:
1.為了避免循環(huán)引用。
2.當對象釋放的時候,系統(tǒng)會對屬性賦值nil,Objective-C 有個特性就是對nil對象發(fā)送消息也就是調(diào)用方法,不會cash。 - delegate:傳遞的是事件(even)
- dataSource:傳遞的是數(shù)據(jù)
- block 和代理的區(qū)別
1.代理更面向過程,block更面向結果
屬性的實質(zhì)是什么?包括哪幾個部分?屬性默認的關鍵字都有哪些?@dynamic 關鍵字和 @synthesize 關鍵字是用來做什么的?
@property = ivar + getter + setter- 基本數(shù)據(jù)
atomic, readwrite, assign - 對象
atomic, readwrite, strong - @dynamic 修飾的屬性,其
getter和setter方法編譯器是不會自動幫你生成,必須自己是實現(xiàn)的。 - @synthesize 修飾的屬性,其
getter和setter方法編譯器是會自動幫你生成,不必自己實現(xiàn),且指定與屬性相對應的成員變量。
atomic 安全么?
- atomic 原子操作,所謂原子,就是不可再化分,已經(jīng)是最小的操作單位(所謂操作指的是對內(nèi)存的讀寫)
- 一個數(shù)據(jù)的線程安全,簡單點來說就是這塊數(shù)據(jù)即使有多個線程同時讀寫,也不會出現(xiàn)數(shù)據(jù)的錯亂,內(nèi)存的最后狀態(tài)是可預見的
- 在 64 位的操作系統(tǒng)下,所有類型的指針,包括
void *都是占用 8 個字節(jié),以 Objective-C 下的NSArray *為例子,如果一個多線程操作這個數(shù)據(jù),會有兩個層級的并發(fā)問題,1、指針本身。2、指針所指向的內(nèi)存,所以這個數(shù)據(jù)array多線程操作的時候,必須分成兩部分來描述,一個是&array這個指針本身,另一個則是它所指向的內(nèi)存array -
@property(atomic)NSArray *array其實修飾的是這個指針,也就是這個 8 字節(jié)內(nèi)存,跟第二部分數(shù)據(jù) n 字節(jié)沒有任何關系,被atomic修飾之后,你不可能隨意去多線程操作這個 8 字節(jié),但是對 8 字節(jié)里面所指向的 n 字節(jié)沒有任何限制 - atomic 只對
get和set方法起作用:我們知道,這個 8 字節(jié)里面存儲的數(shù)據(jù),是 n 字節(jié)數(shù)據(jù)的頭地址,如果更改 8 字節(jié)數(shù)據(jù)的內(nèi)容,那么最后通過這個指針訪問到的數(shù)據(jù)就會完全不一樣
如何令自己所寫的對象具有拷貝功能?
- 遵循
NSCopying協(xié)議,并且實現(xiàn)- (id)copyWithZone:(NSZone *)zone方法 - 如果讓自己的類具備
mutableCopy方法,必須遵守NSMutableCopying,并實現(xiàn)- (id)mutableCopyWithZone:(nullable NSZone *)zone方法
進程和線程的區(qū)別?同步異步的區(qū)別?并行和并發(fā)的區(qū)別?
進程和線程的區(qū)別
- 進程是資源的分配和調(diào)度的一個獨立單元,而線程是 CPU 調(diào)度的基本單元
- 同一個進程中可以包括多個線程,并且線程共享整個進程的資源(寄存器、堆棧、上下文),一個進程至少包括一個線程。
- 進程的創(chuàng)建調(diào)用
fork或者vfork,而線程的創(chuàng)建調(diào)用pthread_create,進程結束后它擁有的所有線程都將銷毀,而線程的結束不會影響同個進程中的其他線程的結束 - 線程是輕兩級的進程,它的創(chuàng)建和銷毀所需要的時間比進程小很多,所有操作系統(tǒng)中的執(zhí)行功能都是創(chuàng)建線程去完成的
- 線程中執(zhí)行時一般都要進行同步和互斥,因為他們共享同一進程的所有資源
- 線程有自己的私有屬性 TCB,線程
id,寄存器、硬件上下文,而進程也有自己的私有屬性進程控制塊 PCB,這些私有屬性是不被共享的,用來標示一個進程或一個線程的標志
同步和異步的區(qū)別
- 同步(synchronous):進程之間的關系不是相互排斥臨界資源的關系,而是相互依賴的關系。進一步的說明:就是前一個進程的輸出作為后一個進程的輸入,當?shù)谝粋€進程沒有輸出時第二個進程必須等待。具有同步關系的一組并發(fā)進程相互發(fā)送的信息稱為消息或事件
- 異步(asynchronous):異步和同步是相對的,同步就是順序執(zhí)行,執(zhí)行完一個再執(zhí)行下一個,需要等待、協(xié)調(diào)運行。異步就是彼此獨立,在等待某事件的過程中繼續(xù)做自己的事,不需要等待這一事件完成后再工作。線程就是實現(xiàn)異步的一個方式。異步是讓調(diào)用方法的主線程不需要同步等待另一線程的完成,從而可以讓主線程干其它的事情
并行和并發(fā)的區(qū)別
- 并發(fā):在操作系統(tǒng)中,是指一個時間段中有幾個程序都處于已啟動運行到運行完畢之間,且這個幾個程序都是在同一個處理機上運行。其中兩種并發(fā)關系分別是同步和互斥。
互斥:進程間相互排斥的使用臨界資源的現(xiàn)象
同步:進程之間的關系不是相互排斥臨界資源的關系,而是相互依賴的關系。進一步說明就是前一個進程的輸出作為后一個進程的輸入,當?shù)谝粋€進程沒有輸出時第二個進程必須等待。具有同步關系的一組并發(fā)進程相互發(fā)送的信息稱為消息或事件。
其中并發(fā)又有偽并發(fā)和真并發(fā),偽并發(fā)是指單核處理器的并發(fā),真并發(fā)是指多核處理器的并發(fā)。 - 并行(parallelism):在單處理器中多道程序設計系統(tǒng)中,進程被交替執(zhí)行,表現(xiàn)出一種并發(fā)的外部特種;在多處理器系統(tǒng)中,進程不僅可以交替執(zhí)行,而且可以重疊執(zhí)行。在多處理器上的程序才可實現(xiàn)并行處理。從而可知,并行是針對多處理器而言的。并行是同時發(fā)生的多個并發(fā)事件,具有并發(fā)的含義,但并發(fā)不一定并行,也亦是說并發(fā)事件之間不一定要同一時刻發(fā)生。
Designated Initializer ?
- 指定初始化函數(shù)對一個類來說非常重要,通常參數(shù)也是最多的,試想每次我們需要創(chuàng)建一個自定義類都需要一堆參數(shù),那豈不是很痛苦。便利初始化函數(shù)就是用來幫我們解決這個問題的,可以讓我們比較的創(chuàng)建對象,同時又可以保證類的成員變量被設置為默認的值。
- 子類如果有指定初始化函數(shù),那么指定初始化函數(shù)實現(xiàn)時必須調(diào)用它的直接父類的指定初始化函數(shù)
- 如果子類有指定初始化函數(shù),那么便利初始化函數(shù)必須調(diào)用自己的其它初始化函數(shù)(包括指定初始化函數(shù)以及其他的便利初始化函數(shù)),不能調(diào)用
super的初始化函數(shù)
能否向編譯后得到的類中增加實例變量?能否向運行時創(chuàng)建的類中添加實例變量?
- 不能向編譯后得到的類增加實例變量,編譯后的類已經(jīng)注冊在
runtime中,類結構體中的objc_ivar_list實例變量的鏈表和instance_size實例變量的內(nèi)存大小已經(jīng)確定,runtime會調(diào)用class_setvarlayout或class_setWeaklvarLayout來處理strong weak引用,所以不能向存在的類中添加實例變量 - 能向運行時創(chuàng)建的類中添加實例變量,運行時創(chuàng)建的類是可以添加實例變量,調(diào)用
class_addIvar函數(shù)。但是需要在調(diào)用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上
給類添加一個屬性后,在類結構體里哪些元素會發(fā)生變化?
- instance_size: 實例的內(nèi)存大小
- objc_ivar_list *ivars: 屬性列表
runloop 的 mode 是用來做什么的?有幾種 mode?
- model 是
runloop里面的模式,不同的模式下的runloop處理的事件和消息有一定的差別,系統(tǒng)默認注冊了 5 個 model 。 - kCFRunLoopDefaultMode: App 的默認 Mode,通常主線程是在這個 Mode 下運行的。
- UITrackingRunLoopMode: 界面跟蹤 Mode,用于
ScrollView追蹤觸摸滑動,保證界面滑動時不受其他 Mode 影響。 - UIInitializationRunLoopMode: 在剛啟動 App 時第進入的第一個 Mode,啟動完成后就不再使用。
- GSEventReceiveRunLoopMode: 接受系統(tǒng)事件的內(nèi)部 Mode,通常用不到。
- kCFRunLoopCommonModes: 這是一個占位的 Mode,沒有實際作用。
- 5 種 model 進行了封裝
NSDefaultRunLoopMode
NSRunLoopCommonModes - NStime 對象默認是在
NSDefaultRunLoopMode下面調(diào)用消息的,但是當我們滑動scrollview的時候,NSDefaultRunLoopMode模式就自動切換到UITrackingRunLoopMode模式下面
isa 指針?

- 對象的
isa指針指向所屬的類 - 類的
isa指針指向了所屬的元類(metaclass) - 元類的
isa指向了根元類(root metaclass),根元類本身的isa指針指向自己,這樣就形成了一個閉環(huán)
Objective-C 中向一個 nil 對象發(fā)送消息將會發(fā)生什么?
- Objective-C 中向
nil發(fā)送消息是完全有效的,只是在運行時不會有任何作用。 - 如果一個方法返回值是一個對象,那么發(fā)送給
nil的消息將返回 0 (nil)。 - 如果方法返回值為指針類型,其指針大小為小于或者等于
sizeof(void*),float,double,long double或者long long的整型標量,發(fā)送給nil的消息將返回 0。 - 如果方法返回值為結構體,發(fā)送給
nil的消息將返回 0。結構體中各個字段的值將都是 0。其他的結構體數(shù)據(jù)類型將不是用 0 填充的。 - 如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給nil的消息的返回值將是未定義的。
.a 與 .framework 庫的區(qū)別?靜態(tài)庫和動態(tài)庫的區(qū)別?
- .a 是一個純二進制文件,不能直接使用,至少要有 .h 文件配合。
- .framework 中除了有二進制文件之外還有資源文件,可以直接使用。
- 靜態(tài)庫:以 .a 和 .framework 為文件后綴名,鏈接時會被完整的復制到可執(zhí)行文件中,被多次使用就有多份拷貝。
- 動態(tài)庫:以
.tbd(之前叫.dylib) 和 .framework 為文件后綴名,鏈接時不復制,程序運行時由系統(tǒng)動態(tài)加載到內(nèi)存,系統(tǒng)只加載一次,多個程序共用(如系統(tǒng)的UIKit.framework等),節(jié)省內(nèi)存。 - Apple 不讓使用自己的動態(tài)庫,iOS8 之后雖然可以上傳含有動態(tài)庫的 App,但是 Apple 不僅需要你動態(tài)庫和 App 的簽名一致,而且蘋果會在你上架的時候再經(jīng)過一次 AppStore 的簽名。
如何讓靜態(tài)庫中的 Category 變得可用?
- Objective-C 不會為方法定義
linker symbols,它只會為每一個類定義linker symbols。如果你使用category擴展了一個已經(jīng)存在的類,那么linker 不會將已有類的實現(xiàn)跟category的實現(xiàn)連接起來,這就導致了調(diào)用靜態(tài)庫中category中新增加的方法時拋出selector not recognized的異常。 - 通過在
Other Linker Flags添加-all_load,它會告訴編譯器“對于所有文檔中的所有對象文件,不管里面的符號有沒有被用到,都載入”,這種方法確實可以,但是會產(chǎn)生比較大的二進制文件。 - 添加
-force_load和指定的路徑,這種方法和-all_load很像,不同的是它只使用指定的歸檔。 - 在
Other Linker Flags中添加-ObjC,這個標識告訴編譯器“如果你在文檔里的對象文件中發(fā)現(xiàn)了 Objective-C 代碼,就把它載入“,Category 里當然也有 Objective-C 代碼。使用這種方法不會載入任何沒有 Objective-C 代碼的文件 - 啟用 Xcode 里 build setting 中的
PerformSingle-Object PreLink,所有的對象文件都會被合并成一個單文件(這不是真正的鏈接,所以叫做預鏈接),這個對象文件(有時被稱做主對象文件(masterobject file)被添加到文檔中?,F(xiàn)在如果主對象文件中的任何符號被認為是“在使用”,整個主對象文件都會被認為在使用,這樣它里面的 Objective-C 部分就會被載入了。因為里面的類都被正常符號化了,所以能使從這樣的靜態(tài)庫中使用所有的category。 - 在只有
category的源文件里添加Fakesymbol。如果你想在runtime里使用category,一定要確保你以某種方法在編譯時引用了fake symbol,這會使得對象文件以及它里面的 Objective-C 代碼被載入。和上面其他的解決方法不一樣,這種解決方法可以控制哪些category可以在runtime里被編譯后的代碼使用(可以通過使用這個符號,使它們被鏈接并變得可用;也可以不使用這個符號,這樣鏈接器就會忽略它)。
BitCode 的理解。
- Bitcode 是被編譯程序的一種中間形式的代碼。包含 Bitcode 配置的程序?qū)?App store 上被編譯(可執(zhí)行的 64 位或 32 位程序)和鏈接。
- Bitcode,做的事情是指令集優(yōu)化,根據(jù)你設備的狀態(tài)去做編譯優(yōu)化,進而提升性能,對包的大小優(yōu)化起不到什么本質(zhì)上的作用。
- APP Thining 是由 App Slicing、On Demand Resources和 Bitcode 組成。
- App Slicing:根據(jù)你設備型號,生成對應資源的 ipa,以節(jié)省空間。
- On Demand Resources:按需加載資源
WKWebView 和 UIWebView 的區(qū)別?無痕瀏覽的實現(xiàn)。
- 在性能、穩(wěn)定性、功能方面有很大提升,直觀體現(xiàn)是內(nèi)存占用變少。
- 允許
JavaScript的Nitro庫加載并使用(UIWebView中限制)。 - 支持了更多的
HTML5特性。 - 高達
60fps的滾動刷新率以及內(nèi)置手勢。 - 將
UIWebViewDelegate與UIWebView重構成了14類與3個協(xié)議(詳見官方文檔)。 - WKWebView的
Cookie存儲在WKWebsiteDataStore中。WKWebsiteDataStore中存儲了包括cookies、disk、memory caches、WebSQL、IndexedDB數(shù)據(jù)庫和本地存儲等web內(nèi)容。
//defaultDataStore 是默認選擇的存儲容器
+ (WKWebsiteDataStore *)defaultDataStore;
//nonPersistentDataStore 會禁止任何數(shù)據(jù)寫入文件系統(tǒng),可用于無痕瀏覽
+ (WKWebsiteDataStore *)nonPersistentDataStore;
//可以查看到容器中存儲的網(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。 - 下載任務方式:
NSURLConnection下載文件時,先是將整個文件下載到內(nèi)存,然后再寫入到沙盒,如果文件比較大,就會出現(xiàn)內(nèi)存暴漲的情況。而使用NSURLSessionUploadTask下載文件,會默認下載到沙盒中的tem文件中,不會出現(xiàn)內(nèi)存暴漲的情況,但是在下載完成后會把tem中的臨時文件刪除,需要在初始化任務方法時,在completionHandler回調(diào)中增加保存文件的代碼。 - 請求方式的控制:
NSURLConnection實例化對象,實例化開始,默認請求就發(fā)送(同步發(fā)送),不需要調(diào)用start方法。而cancel可以停止請求的發(fā)送,停止后不能繼續(xù)訪問,需要創(chuàng)建新的請求。NSURLSession有三個控制方法,取消(cancel)、暫停(suspend)、繼續(xù)(resume),暫停以后可以通過繼續(xù)恢復當前的請求任務。 - 斷點續(xù)傳實現(xiàn)方式 :·NSURLConnection· 進行斷點下載,通過設置訪問請求的
HTTPHeaderField的Range屬性,開啟運行循環(huán),NSURLConnection的代理方法作為運行循環(huán)的事件源,接收到下載數(shù)據(jù)時代理方法就會持續(xù)調(diào)用,并使用NSOutputStream管道流進行數(shù)據(jù)保存。NSURLSession進行斷點下載,當暫停下載任務后,如果downloadTask(下載任務)為非空,調(diào)用cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler這個方法,這個方法接收一個參數(shù),完成處理代碼塊,這個代碼塊有一個NSData參數(shù)resumeData,如果resumeData非空,我們就保存這個對象到視圖控制器的resumeData屬性中,在點擊再次下載時,通過調(diào)用[ [self.session downloadTaskWithResumeData:self.resumeData] resume]方法進行繼續(xù)下載操作,使用NSURLSession進行斷點下載更加便捷. - 配置信息:
NSURLSession的構造方法(sessionWithConfiguration:delegate:delegateQueue)中有一個NSURLSessionConfiguration類的參數(shù)可以設置配置信息,其決定了cookie,安全和高速緩存策略,最大主機連接數(shù),資源管理,網(wǎng)絡超時等配置。NSURLConnection不能進行這個配置,相比較與NSURLConnection依賴與一個全局的配置對象,缺乏靈活性而言,NSURLSession有很大改進。 -
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,圖片解碼等與平臺相關的模塊 - JavaScriptCore:
JS虛擬機,主要用于操作DOM,解析執(zhí)行JavaScript代碼
WebKit - WKWebView:網(wǎng)頁的渲染與展示,通過
WKWebViewConfiguration可以進行配置。 - WKWebViewConfiguration:這個類專門用來配置
WKWebView。 - WKPreference:這個類用來進行相關設置。
- WKProcessPool:這個類用來配置進程池,與網(wǎng)頁視圖的資源共享有關。
- WKUserContentController:這個類主要用來做
native與JavaScript的交互管理。 - WKUserScript:用于進行
JavaScript注入。 - WKScriptMessageHandler:這個類專門用來處理
JavaScript調(diào)用native的方法。 - WKNavigationDelegate:網(wǎng)頁跳轉(zhuǎn)間的導航管理協(xié)議,這個協(xié)議可以監(jiān)聽網(wǎng)頁的活動。
- WKNavigationAction:網(wǎng)頁某個活動的示例化對象。
- WKUIDelegate:用于交互處理
JavaScript中的一些彈出框。 - WKBackForwardList:堆棧管理的網(wǎng)頁列表。
- WKBackForwardListItem:每個網(wǎng)頁節(jié)點對象。
WKWebView 在 WebKit 中的初始化流程:
- 根據(jù)配置項
WKWebViewConfiguration創(chuàng)建新WKWebView,同時會初始化WKScrollView和WKContentView; -
WKContentView從進程池WKProcessPool中分配WebProcessProxy和WebPageProxy,同時根據(jù)當前Page初始化WKBrowsingContextController,提供了大部分交互操作功能; -
WKWebView在獨立于App Process進程之外的Network Process進程中執(zhí)行網(wǎng)絡請求,請求數(shù)據(jù)不經(jīng)過主進程,因此,在WKWebView上直接使用NSURLProtocol無法攔截請求。
一個完整的網(wǎng)絡請求代理攔截處理流程:
-
WKBrowsingContextController通過registerSchemeForCustomProtocol向WebProcessPool注冊全局自定義scheme -
WebProcessPool使用已注冊的scheme初始化Network Process進程配置,同時設置CustomProtocolManager,負責把網(wǎng)絡請求通過 IPC 發(fā)送到App Process進程、也接收從App Process進程返回的網(wǎng)絡響應response -
CustomProtocolManager注冊了NSURLProtocol的子類WKCustomProtocol,負責攔截網(wǎng)絡請求處理 -
CustomProtocolManagerProxy中的WKCustomProtocolLoader使用NSURLConnection發(fā)送實際的網(wǎng)絡請求,并將響應response返回給CustomProtocolManager - 詳見NSURLProtocol-WebKitSupport
__weak & __unsafe_unretained 的區(qū)別
- __unsafe_unretained: 不會對對象進行
retain,當對象銷毀時,依然會指向之前的內(nèi)存空間(野指針)。 - __weak:不會對對象進行
retain,當對象銷毀時,會自動置為nil。
NSCatch 和 NSDictionary區(qū)別?
-
NSCache在系統(tǒng)內(nèi)存很低時會自動釋放對象。 -
NSCache是線程安全的,在進行多線程操作時,不需要進行加鎖。 -
NSCatch可以給對象設置上限,用以限制緩存中的對象總個數(shù)。 -
NSCache不會拷貝Key。
實例方法與類方法的區(qū)別
實例方法
- 減號 - 開頭。
- 只能由對象來調(diào)用。
- 對象方法中能訪問當前對象的成員變量(實例變量)。
-
self是對象的首地址。
類方法
- 加號 + 開頭。
- 只能由類(名)來調(diào)用。
- 類方法中不能訪問成員變量(實例變量)。
-
self是Class。
