一、談?wù)凴untime
1、OC是一門動(dòng)態(tài)性比較強(qiáng)的編程語言,允許很多操作推遲到程序運(yùn)行時(shí)再進(jìn)行
2、OC的動(dòng)態(tài)性就是由Runtime來支撐和實(shí)現(xiàn)的,Runtime是一套C語言的API,封裝了很多動(dòng)態(tài)性相關(guān)的函數(shù)
3、平時(shí)編寫的OC代碼,底層都是轉(zhuǎn)換成了Runtime API進(jìn)行調(diào)用
利用如time我們可以做很多事情 如
1、利用關(guān)聯(lián)對(duì)象(AssociatedObject)給分類添加屬性
2、遍歷類的所有成員變量(修改textfield的占位文字顏色、字典轉(zhuǎn)模型、自動(dòng)歸檔解檔)
3、交換方法實(shí)現(xiàn)(交換系統(tǒng)的方法)
4、利用消息轉(zhuǎn)發(fā)機(jī)制解決方法找不到的異常問題
OC中方法的調(diào)用都是轉(zhuǎn)化為objc_msgSend函數(shù)的調(diào)用
objc_msgSend函數(shù)可以分為三個(gè)階段
第一個(gè)階段是:消息發(fā)送階段
首先判斷消息的接受者是否存在 如果不存在則直接返回如果存在則 從自己類的方法緩存列表中查找該方法,如果存在則執(zhí)行 如果不存在則去自己類的方法列表中查找,如果存在則緩存到自己類的方法緩存列表中 然后在執(zhí)行,如果不存在則去父類的方法緩存列表中查找,如果存在則緩存到自己類的方法緩存列表中 然后執(zhí)行,如果不存在 則去父父類的方法列表中查找,如果存在 則緩存到自己類的方法緩存列表中, 如果不存在則進(jìn)入第二不方法動(dòng)態(tài)解析階段
第二階段是:方法動(dòng)態(tài)解析階段
首先判斷方法是否動(dòng)態(tài)解析過,如果之前已經(jīng)有過動(dòng)態(tài)解析 則直接進(jìn)入第一步消息發(fā)送階段
如果沒有過動(dòng)態(tài)解析則調(diào)用+resolveInstanceMethod:或則+resoveClassMethod:方法來動(dòng)態(tài)解析 然后標(biāo)記為已經(jīng)動(dòng)態(tài)解析 最后重新走“消息發(fā)送”的流程
在此階段 我們可以添加一個(gè)新的方法來代替原來的方法 如果在此階段不做任何處理 則直接進(jìn)入第三步 消息轉(zhuǎn)發(fā)階段
第三階段是:消息轉(zhuǎn)發(fā)階段
1、首先調(diào)用forwardingTargetForSelector:方法 在此方法中:如果返回值不為空 則直接給返回值轉(zhuǎn)發(fā)消息
如果返回值為空否則進(jìn)入第2步 調(diào)用方法簽名函數(shù)
2、調(diào)用methodSignatureForSelector:方法(方法簽名函數(shù))在此方法中:
如果返回值為空 則直接調(diào)用 調(diào)用doesNotRecognizeSelector:方法 然后程序報(bào)錯(cuò):unrecognized selector sent to instance 經(jīng)典錯(cuò)誤
如果返回值不為空 則直接進(jìn)入第3步 調(diào)用 forwardInvocation方法
3、forwardInvocation:方法
開發(fā)人員可以在此方法中處理調(diào)用的方法
二、談?wù)凴unloop
顧名思義就是運(yùn)行循環(huán),在程序運(yùn)行過程中循環(huán)做一些事情
1、保持程序的持續(xù)運(yùn)行
2、處理App中的各種事件(比如觸摸事件、定時(shí)器事件等)
3、節(jié)省CPU資源,提高程序性能:該做事時(shí)做事,該休息時(shí)休息
runloop與線程之間的關(guān)系
1、每條線程都有唯一的一個(gè)與之對(duì)應(yīng)的RunLoop對(duì)象
2、RunLoop保存在一個(gè)全局的Dictionary里,線程作為key,RunLoop作為value
3、線程剛創(chuàng)建時(shí)并沒有RunLoop對(duì)象,RunLoop會(huì)在第一次獲取它時(shí)創(chuàng)建([NSRunLoop currentRunLoop])
4、RunLoop會(huì)在線程結(jié)束時(shí)銷毀
5、主線程的RunLoop已經(jīng)自動(dòng)獲取(創(chuàng)建),子線程默認(rèn)沒有開啟RunLoop
獲取runloop對(duì)象的方法
[NSRunLoop currentRunLoop]; // 獲得當(dāng)前線程的RunLoop對(duì)象
[NSRunLoop mainRunLoop]; // 獲得主線程的RunLoop對(duì)象
CFRunLoopGetCurrent(); // 獲得當(dāng)前線程的RunLoop對(duì)象
CFRunLoopGetMain(); // 獲得主線程的RunLoop對(duì)象
三、你做了什么工作使崩潰率下降的 (使用什么工具定位崩潰,崩潰的補(bǔ)救措施)
答:線上項(xiàng)目中集成第三方bug收集工具 bugly 然后配置好符號(hào)表(dSYM),app每次崩潰bugly后臺(tái)都會(huì)有相應(yīng)的崩潰信息,而且能夠具體的某一行,根據(jù)崩潰信息查漏補(bǔ)缺。
開發(fā)過程中根據(jù)Xcode設(shè)置全局?jǐn)帱c(diǎn)定位崩潰某一行。
測試過程中可以根據(jù)bugly后臺(tái)查看崩潰信息,也可以使用Xcode查看手機(jī)里面的log信息來分析crash信息。
四、使用什么方式使子線程永駐
開啟子線程的runloop
五、https 中間人攻擊(是怎樣攻擊的)
HTTPS 中間人攻擊。也就是通訊雙方中插入一個(gè)中間人,通訊雙方的對(duì)方已經(jīng)變成中間人了,而不是原本的對(duì)方。
HTTPS 協(xié)議之所以是安全的是因?yàn)?HTTPS 協(xié)議會(huì)對(duì)傳輸?shù)臄?shù)據(jù)進(jìn)行加密,而加密過程是使用了非對(duì)稱加密實(shí)現(xiàn)。但其實(shí),HTTPS 在內(nèi)容傳輸?shù)募用苌鲜褂玫氖菍?duì)稱加密,非對(duì)稱加密只作用在證書驗(yàn)證階段。
HTTPS的整體過程分為證書驗(yàn)證和數(shù)據(jù)傳輸階段
① 證書驗(yàn)證階段
客戶端發(fā)起 HTTPS 請(qǐng)求
服務(wù)端返回 HTTPS 證書
客戶端驗(yàn)證證書是否合法,如果不合法則提示告警
② 數(shù)據(jù)傳輸階段
當(dāng)證書驗(yàn)證合法后,客戶端在本地生成隨機(jī)數(shù)
通過公鑰加密隨機(jī)數(shù),并把加密后的隨機(jī)數(shù)傳輸?shù)椒?wù)端
服務(wù)端通過私鑰對(duì)隨機(jī)數(shù)進(jìn)行解密
服務(wù)端通過客戶端傳入的隨機(jī)數(shù)構(gòu)造對(duì)稱加密算法,對(duì)返回結(jié)果內(nèi)容進(jìn)行加密后傳輸
為什么數(shù)據(jù)傳輸是用對(duì)稱加密?
首先,非對(duì)稱加密的加解密效率是非常低的,而 http 的應(yīng)用場景中通常端與端之間存在大量的交互,非對(duì)稱加密的效率是無法接受的;另外,在 HTTPS 的場景中只有服務(wù)端保存了私鑰,一對(duì)公私鑰只能實(shí)現(xiàn)單向的加解密,所以 HTTPS 中內(nèi)容傳輸加密采取的是對(duì)稱加密,而不是非對(duì)稱加密。
為什么需要 CA 認(rèn)證機(jī)構(gòu)頒發(fā)證書?
HTTP 協(xié)議被認(rèn)為不安全是因?yàn)閭鬏斶^程容易被監(jiān)聽者勾線監(jiān)聽、偽造服務(wù)器,而 HTTPS 協(xié)議主要解決的便是網(wǎng)絡(luò)傳輸?shù)陌踩詥栴}。首先我們假設(shè)不存在認(rèn)證機(jī)構(gòu),任何人都可以制作證書,這帶來的安全風(fēng)險(xiǎn)便是經(jīng)典的“中間人攻擊”問題?!爸虚g人攻擊”的具體過程如下:
過程原理:
1、客戶端請(qǐng)求被劫持(如DNS劫持等),所有請(qǐng)求均發(fā)送到中間人的服務(wù)器
2、中間人服務(wù)器返回中間人自己的證書
3、客戶端創(chuàng)建隨機(jī)數(shù),通過中間人證書的公鑰對(duì)隨機(jī)數(shù)加密后傳送給中間人,然后憑隨機(jī)數(shù)構(gòu)造對(duì)稱加密對(duì)傳輸內(nèi)容進(jìn)行加密傳輸
4、中間人因?yàn)閾碛锌蛻舳说碾S機(jī)數(shù),可以通過對(duì)稱加密算法進(jìn)行內(nèi)容解密
5、中間人以客戶端的請(qǐng)求內(nèi)容再向正規(guī)網(wǎng)站發(fā)起請(qǐng)求
6、因?yàn)橹虚g人與服務(wù)器的通信過程是合法的,正規(guī)網(wǎng)站通過建立的安全通道返回加密后的數(shù)據(jù)
7、中間人憑借與正規(guī)網(wǎng)站建立的對(duì)稱加密算法對(duì)內(nèi)容進(jìn)行解密
8、中間人通過與客戶端建立的對(duì)稱加密算法對(duì)正規(guī)內(nèi)容返回的數(shù)據(jù)進(jìn)行加密傳輸
9、客戶端通過與中間人建立的對(duì)稱加密算法對(duì)返回結(jié)果數(shù)據(jù)進(jìn)行解密
由于缺少對(duì)證書的驗(yàn)證,所以客戶端雖然發(fā)起的是 HTTPS 請(qǐng)求,但客戶端完全不知道自己的網(wǎng)絡(luò)已被攔截,傳輸內(nèi)容被中間人全部竊取。
Q: HTTPS 為什么安全?
A: 因?yàn)?HTTPS 保證了傳輸安全,防止傳輸過程被監(jiān)聽、防止數(shù)據(jù)被竊取,可以確認(rèn)網(wǎng)站的真實(shí)性。
Q: HTTPS 的傳輸過程是怎樣的?
A: 客戶端發(fā)起 HTTPS 請(qǐng)求,服務(wù)端返回證書,客戶端對(duì)證書進(jìn)行驗(yàn)證,驗(yàn)證通過后本地生成用于改造對(duì)稱加密算法的隨機(jī)數(shù),通過證書中的公鑰對(duì)隨機(jī)數(shù)進(jìn)行加密傳輸?shù)椒?wù)端,服務(wù)端接收后通過私鑰解密得到隨機(jī)數(shù),之后的數(shù)據(jù)交互通過對(duì)稱加密算法進(jìn)行加解密。
Q: 為什么需要證書?
A: 防止”中間人“攻擊,同時(shí)可以為網(wǎng)站提供身份證明。
Q: 使用 HTTPS 會(huì)被抓包嗎?
A: 會(huì)被抓包,HTTPS 只防止用戶在不知情的情況下通信被監(jiān)聽,如果用戶主動(dòng)授信,是可以構(gòu)建“中間人”網(wǎng)絡(luò),代理軟件可以對(duì)傳輸內(nèi)容進(jìn)行解密。
參考地址:<u>https://juejin.cn/post/6844904065227292685</u>
六、KVC 原理
1、KVC的全稱是Key-Value Coding、俗稱“鍵值編碼”、可以通過一個(gè)key來訪問某一個(gè)屬性。
2、常見的API有四種
setValue: forKey
setValue: forKeyPath
valueForKey:
valueForKeyPath
forKey 和 forKeyPath 主要區(qū)別是路徑區(qū)別
七、KVO實(shí)現(xiàn)原理
KVO的原理:
1、當(dāng)實(shí)例對(duì)象 進(jìn)行KVO觀察時(shí)候,會(huì)利用RuntimeAPI動(dòng)態(tài)生成一個(gè)子類,然后將對(duì)象的isa指向新生成的子類
2、KVO本質(zhì)上是監(jiān)聽屬性的setter方法,只要被觀察對(duì)象有成員變量和對(duì)應(yīng)的set方法,調(diào)用Foundation的_NSSetValueAndNotify函數(shù)這個(gè)函數(shù)內(nèi)部會(huì)執(zhí)行 willChangeVlaueForKey函數(shù)、父類的setter方法 和didChangeVlaueForKey函數(shù)
3、子類會(huì)重寫父類的set、class、dealloc方法
4、當(dāng)觀察對(duì)象移除所有的監(jiān)聽后,會(huì)將觀察對(duì)象的isa指向原來的類
5、當(dāng)觀察對(duì)象的監(jiān)聽全部移除后,動(dòng)態(tài)生成的類不會(huì)注銷,而是留在下次觀察時(shí)候再使用,避免反復(fù)創(chuàng)建中間子類
八、為什么ui在主線程刷新
UI刷新在主線程主要有兩個(gè)原因
第一:安全
因?yàn)閁IKit框架不是線程安全的,當(dāng)多個(gè)線程同時(shí)操作UI的時(shí)候,搶奪資源,導(dǎo)致崩潰,UI異常等問題。
第二:用戶體驗(yàn)
iOS中只有主線程才能立即刷新UI。在子線程中是不能夠更新UI,我們看到的子線程能夠更新UI的原因是,等到子線程執(zhí)行完畢,自動(dòng)進(jìn)入了主線程去執(zhí)行子線程中更新UI的代碼。由于子線程執(zhí)行時(shí)間非常短暫,讓我們誤以為子線程可以更新UI。如果子線程一直在運(yùn)行,則無法更新UI,因?yàn)闆]有辦法進(jìn)入主線程。
九、block有幾種,底層實(shí)現(xiàn),以及如何持有外部變量的
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對(duì)象
block 有三種類型分別如下
· __NSGlobalBlock
· __NSStackBlock
· __NSMallocBlock
只要沒有訪問 auto的變量 都是 NSGlobalBlock
訪問了auto變量 但是沒有調(diào)用 copy 都是 NSStackBlock
即訪問了auto變量又調(diào)用了copy 則是 NSMallocBlock
注意:NSGlobalBlock即使調(diào)用了copy 它還是 NSGlobalBlock
__NSStackBlock__調(diào)用了 copy 它就變成了 __NSMallocBlock__
__NSMallocBlock__ 調(diào)用了copy 只是使引用計(jì)數(shù)增加 其類型還是 __NSMallocBlock__
十、load和initlize的區(qū)別
調(diào)用時(shí)機(jī)不同
load方法在runtime類、分類加載的時(shí)候調(diào)用且只調(diào)用一次 如果出現(xiàn)繼承時(shí)
在調(diào)用子類的load方法時(shí)首先調(diào)用父類的load方法 其他子類的load方法則按照編譯順序來決定
initialize方法是在類第一次接收到消息時(shí)調(diào)用,
出現(xiàn)繼承時(shí)父類的initialize方法可能會(huì)調(diào)用多次(父類的initialize調(diào)用多次并不代表父類會(huì)初始化多次,父類只會(huì)初始化一次)
調(diào)用方式不同
load方式是通過指針函數(shù)直接調(diào)用
initialize是通過objc_msgSend來調(diào)用
十一、性能優(yōu)化
App的性能優(yōu)化主要從兩個(gè)方面
CPU 和 GPU
CPU 和 GPU 在屏幕成像過程中起著至關(guān)重要的作用
CPU 主要負(fù)責(zé) 對(duì)象的創(chuàng)建和銷毀、 對(duì)象屬性的調(diào)整、布局計(jì)算、文本計(jì)算和排版、圖片的格式轉(zhuǎn)換和解碼、圖像的繪制工作
GPU 主要負(fù)責(zé)紋理渲染
性能優(yōu)化主要思路就是 盡可能減少 CPU和GPU的資源消耗
在CUP方面
1、盡量使用輕量級(jí)的對(duì)象、比如在使用不到事件處理的地方 可以考慮使用CALayer來取代UIView
2、不要頻繁調(diào)用UIView的屬性,比如 frame、bounds、transform 等屬性,盡量減少不必要的修改
3、盡量提前計(jì)算好布局、在需要的時(shí)候一次性調(diào)整對(duì)應(yīng)的屬性、不要多次修改屬性
4、AutoLayout會(huì)比直接設(shè)置frame消耗更多的CPU資源
5、圖片的size最好和UIImageView的size的保持一致
6、控制一下子線程的最大并非數(shù)量
7、耗時(shí)的操作盡量放在子線程中處理
比如,文本處理(尺寸計(jì)算、繪制)
圖片處理(解碼、繪制)
GPU方面
1、盡量避免段時(shí)間內(nèi)大量圖片的顯示,盡可能將多張圖片合成一張顯示
2、GPU最大處理紋理是4096 x 4096 一旦超過這個(gè)尺寸就會(huì)占用CPU資源來處理
3、盡量減少試圖的數(shù)量和層數(shù)
4、盡量減少離屏渲染
十二、推送相關(guān)知識(shí)點(diǎn)
推送原理:
1、App向iOS設(shè)備發(fā)送一個(gè)注冊(cè)通知,用戶需要同意系統(tǒng)發(fā)送推送。
2、iOS設(shè)備向蘋果遠(yuǎn)程推送服務(wù)器發(fā)送App的Bundle Id和設(shè)備的UDID
3、蘋果推送服務(wù)器根據(jù)設(shè)備的UDID和App的Bundle Id生成deviceToken再發(fā)回給App
4、App再將deviceToken發(fā)送給遠(yuǎn)程推送服務(wù)器(自己的服務(wù)器), 由服務(wù)器保存在數(shù)據(jù)庫中。
5、當(dāng)自己的服務(wù)器想發(fā)送推送時(shí), 會(huì)把用戶的devicetoken和消息內(nèi)容一起發(fā)送給蘋果遠(yuǎn)程推送服務(wù)器
6、蘋果遠(yuǎn)程推送服務(wù)器在自身已注冊(cè)Push服務(wù)的iOS設(shè)備列表中。查找有對(duì)應(yīng)標(biāo)識(shí)的iOS設(shè)備,并將消息發(fā)送到iOS設(shè)備
7、iOS設(shè)備接收到蘋果遠(yuǎn)程服務(wù)器push過來的消息之后,找到相應(yīng)的應(yīng)用程序。并依照設(shè)定彈出Push通知
十三、MVC、MVVM、MVP相關(guān)知識(shí)點(diǎn)
MVC
MVC也就是Model View Controller(模型 視圖 控制器)
MVC的特點(diǎn)就是view上顯示什么內(nèi)容取決于model 。view和model之間的通信是通過Controler來完成 Controler負(fù)責(zé)初始化 Model且對(duì)model進(jìn)行讀寫調(diào)用然后并將 Model的值 傳遞給 View 去解析展示。
MVC有優(yōu)點(diǎn)也有缺點(diǎn)
優(yōu)點(diǎn)是
將數(shù)據(jù)與視圖分離開來,有一定可閱讀性。降低了代碼的耦合性有利于代碼的維護(hù)。
缺點(diǎn)
1、自身設(shè)計(jì)的缺點(diǎn)
在 MVC 模式中 view 將用戶交互通知給控制器。view 的控制器通過更新 Model 來反應(yīng)狀態(tài)的改變。Model(通常使用 Key-Value-Observation)通知控制器來更新他們負(fù)責(zé)的 view。大多數(shù) iOS 應(yīng)用程序的代碼使用這種方式來組織。
2、愈發(fā)笨重的 Controller
大量的代碼被堆放在controller中使Controller變得越來越臃腫,臃腫的Controller 不僅要管理自身的屬性狀態(tài)還要遵循許多協(xié)議,導(dǎo)致協(xié)議的響應(yīng)代碼和 controller 的邏輯代碼混淆在一起很難管理和測試。
3、太過于輕量級(jí)的 Model
ARC 普及以后我們?cè)?Model 層的實(shí)現(xiàn)文件中基本上看不到代碼,同時(shí)與控制器的代碼越來厚重形成強(qiáng)烈的反差。
4、遺失的網(wǎng)絡(luò)邏輯
開發(fā)過程中,我們的大部分?jǐn)?shù)據(jù)來源于網(wǎng)絡(luò)請(qǐng)求,如果網(wǎng)絡(luò)請(qǐng)求放在model/view中,由于網(wǎng)絡(luò)調(diào)用大部分使用異步,可能會(huì)出現(xiàn)網(wǎng)絡(luò)請(qǐng)求比持有它的 Model /view生命周期更長,這樣會(huì)導(dǎo)致網(wǎng)絡(luò)請(qǐng)求被提前釋放。放到controller中又使控制器越來越臃腫。
MVVM
MVVM 即 Model View(可能是View 也可能是ViewController) ViewModel(模型 視圖 視圖模型)
MVVM衍生于MVC,是對(duì) MVC 的一種演進(jìn),它促進(jìn)了 UI 代碼與業(yè)務(wù)邏輯的分離。它正式規(guī)范了視圖和控制器緊耦合的性質(zhì),并引入新的組件。
在MVVM 中,view 和 view controller正式聯(lián)系在一起,我們把它們視為一個(gè)組件
view 和 view controller 都不能直接引用model,而是引用視圖模型(viewModel)
viewModel 是一個(gè)放置用戶輸入驗(yàn)證邏輯,視圖顯示邏輯,發(fā)起網(wǎng)絡(luò)請(qǐng)求和其他代碼的地方
使用MVVM會(huì)輕微的增加代碼量,但總體上減少了代碼的復(fù)雜性
MVP
MVP模式是MVC模式的一個(gè)演化版本 MVP全稱Model-View-Presenter
Model:與MVC中的model沒有太大的區(qū)別。主要提供數(shù)據(jù)的存儲(chǔ)功能,一般都是用來封裝網(wǎng)絡(luò)獲取的json數(shù)據(jù)的集合。Presenter通過調(diào)用Model進(jìn)行對(duì)象交互。
View:這里的View與MVC中的V又有一些小差別,這個(gè)View可以是viewcontroller、view等控件。Presenter通過向View傳model數(shù)據(jù)進(jìn)行交互。
Presenter:作為model和view的中間人,從model層獲取數(shù)據(jù)之后傳給view,使得View和model沒有耦合。
總得來說MVP的好處就是解除view與model的耦合,使得view或model有更強(qiáng)的復(fù)用性。
十四、App體積優(yōu)化
1、刪除項(xiàng)目中未使用的圖片
2、刪除項(xiàng)目中未使用的類
十五、啟動(dòng)時(shí)間優(yōu)化
App的啟動(dòng)分為冷啟動(dòng)和熱啟動(dòng)
冷啟動(dòng)是從零開始啟動(dòng)app
熱啟動(dòng)是app已經(jīng)在內(nèi)存中,在后臺(tái)運(yùn)行,然后再次點(diǎn)擊app圖標(biāo)啟動(dòng)app
一般我們優(yōu)化啟動(dòng)時(shí)間 所指的就是優(yōu)化app 的冷啟動(dòng)時(shí)間。
App 冷啟動(dòng)一般分為三個(gè)階段
第一個(gè)階段是 dyld Apple的動(dòng)態(tài)鏈接器,可以用來裝載Mach-O文件(可執(zhí)行文件、動(dòng)態(tài)庫等)
啟動(dòng)APP時(shí),dyld所做的事情有
1、裝載APP的可執(zhí)行文件,同時(shí)會(huì)遞歸加載所有依賴的動(dòng)態(tài)庫
2、當(dāng)dyld把可執(zhí)行文件、動(dòng)態(tài)庫都裝載完畢后,會(huì)通知Runtime進(jìn)行下一步的處理
第二個(gè)階段:runtime
1、調(diào)用map_images進(jìn)行可執(zhí)行文件內(nèi)容的解析和處理
2、調(diào)用所有Class和Category的+load方法
3、進(jìn)行各種objc結(jié)構(gòu)的初始化(注冊(cè)O(shè)bjc類 、初始化類對(duì)象等等)
4、調(diào)用C++靜態(tài)初始化器和attribute((constructor))修飾的函數(shù)
第三個(gè)階段 main
也就是UIApplicationMain函數(shù),AppDelegate的application:didFinishLaunchingWithOptions:方法 到根視圖控制器頁面顯示的這一段
按照不同的階段
第一階段:dyld
1、減少動(dòng)態(tài)庫、合并一些動(dòng)態(tài)庫(定期清理不必要的動(dòng)態(tài)庫)
2、減少Objc類、分類的數(shù)量、減少Selector數(shù)量(定期清理不必要的類、分類)
3、減少C++虛函數(shù)數(shù)量
第二階段:runtime
1、用+initialize方法和dispatch_once取代所有的attribute((constructor))、C++靜態(tài)構(gòu)造器、ObjC的+load
第三階段:main
在不影響用戶體驗(yàn)的前提下,盡可能將一些操作延遲,不要全部都放在finishLaunching方法中
按需加載
十六、多線程
iOS 多線程種類有4種
1、pthread 基于C語言可以跨平臺(tái) 手動(dòng)管理線程的生命周期 由于使用比較復(fù)雜幾乎很少使用
2、NSThread 簡單易用 可以直接操作線程對(duì)象,是基于OC語言的 手動(dòng)管理線程的生命周期 偶爾使用
3、GCD 基于C語言,能夠充分利用設(shè)備的多核,自動(dòng)管理線程的生命周期 經(jīng)常使用
4、NSOperation 基于OC是對(duì)GCD的封裝 自動(dòng)關(guān)線程的生命周期 經(jīng)常使用
我在開發(fā)中經(jīng)常使用的是GCD 因?yàn)?/p>
1、他可以多核的并行運(yùn)算
2、會(huì)自動(dòng)利用更多的CPU內(nèi)核
3、hi自動(dòng)管理線程的生命周期
4、使用簡單
CGD有兩個(gè)核心的概念
1、任務(wù)
2、隊(duì)列
任務(wù):分為同步和異步
同步和異步的區(qū)別在于能不能開辟新的線程
同步:不具備開辟線程的能力 任務(wù)只在當(dāng)前線程執(zhí)行
異步:具備開辟線程的能力,可以在新的線程中執(zhí)行任務(wù)
隊(duì)列:分為串行隊(duì)列和并發(fā)隊(duì)列
串行隊(duì)列和并發(fā)隊(duì)列主要的區(qū)別是能否同時(shí)執(zhí)行多個(gè)任務(wù)
串行隊(duì)列:讓任務(wù)一個(gè)接著一個(gè)的執(zhí)行
并發(fā)隊(duì)列:任務(wù)可以同時(shí)執(zhí)行,并發(fā)隊(duì)列只有在異步中才有效
NSoperation和NSOPreationQueue:是對(duì)GCD更高一層的封裝,但是比 GCD 更簡單易用、代碼可讀性也更高,他也是自動(dòng)管理線程的生命周期。
NSoperation和NSOPreationQueue 可以設(shè)定任務(wù)執(zhí)行的優(yōu)先級(jí)、可以隨時(shí)取消一個(gè)操作的執(zhí)行、也可以添加多個(gè)操作的依賴關(guān)系。
十七、線程鎖
線程鎖出現(xiàn)的原因就是解決多線程的安全隱患
當(dāng)一塊資源被多個(gè)線程同時(shí)訪問的時(shí)候很容易引發(fā)數(shù)據(jù)錯(cuò)亂
解決這一問題的方案就是對(duì)線程加鎖
iOS的鎖有很多種
如
OSSpinLock //自旋鎖 (iOS 10以后被os_unfair_lock替換)
os_unfair_lock //
pthread_mutex //互斥鎖
dispatch_semaphore //信號(hào)量
dispatch_queue(DISPATCH_QUEUE_SERIAL)
NSLock
NSRecursiveLock
NSCondition
NSConditionLock
@synchronized
1.3 什么是 懶加載?
懶加載 也稱為延遲加載, 核心思想是把對(duì)象的實(shí)例化盡量延遲,直到真正用到的時(shí)候才將其實(shí)例化,
這樣做的好處是可以減輕大量對(duì)象在實(shí)例化時(shí)對(duì)資源的消耗,而不是在程序初始化的時(shí)候 就預(yù)先將對(duì)象實(shí)例化,
懶加載可以將對(duì)象的實(shí)例化代碼從初始化方法中獨(dú)立出來. 提高代碼可讀性,
1.5 什么是謂詞?
簡單的說 謂詞就是一個(gè)過濾器, 符合條件的留下, 不符合條件的刪除.
謂詞本身就代表了一個(gè)邏輯條件, 計(jì)算謂詞之后 返回的結(jié)果永遠(yuǎn)為 BOOL 類型的值.
而謂詞最常用的功能就是對(duì)集合進(jìn)行過濾,當(dāng)程序使用謂詞對(duì)集合元素進(jìn)行過濾時(shí), 程序會(huì)自動(dòng)遍歷其元素, 并根據(jù)集合元素來計(jì)算謂詞的值,
當(dāng)這個(gè)集合中的元素 計(jì)算謂詞并返回YES時(shí), 這個(gè)元素才會(huì)被保留下來. 并重新組合成一個(gè)集合返回 .
1.7 OC 的數(shù)組或字典中, 添加nil 對(duì)象會(huì)有什么問題?
數(shù)組或字典如果通過 addObject 函數(shù)添加 nil 會(huì)崩潰.
但初始化時(shí) 通過 initWithObjects方法里面的nil 會(huì)被編譯器過濾去掉不會(huì)有影響,
另外如果使用語法糖初始化數(shù)組或字典也不可以有nil , 此時(shí) nil 不會(huì)被過濾 也會(huì)崩潰.
1.10 AppDelegate 中主要的幾個(gè)回調(diào)方法?
application (應(yīng)用程序.) 應(yīng)用啟動(dòng)并進(jìn)入初始化時(shí)會(huì)調(diào)用該方法并發(fā)生通知, 這個(gè)階段會(huì)實(shí)例化 根視圖控制器,.
applicationDidBecomeActice ( 變得活躍 ) 應(yīng)用進(jìn)入前臺(tái)并處于活動(dòng)狀態(tài) 調(diào)用該方法并發(fā)生通知, 這個(gè)階段可以恢復(fù) UI 的狀態(tài),
applicationWillResignActive (退出活動(dòng)) 應(yīng)用從活動(dòng)狀態(tài) 進(jìn)入非活動(dòng)狀態(tài)時(shí) 調(diào)用該方法并發(fā)生通知, 這個(gè)階段可以保存 UI 的狀態(tài),
applicationDidEnterBackground ( 進(jìn)入后臺(tái) ) 應(yīng)用進(jìn)入前臺(tái), 但是還沒有處于活動(dòng)狀態(tài)時(shí) 調(diào)用該方法并發(fā)生通知, 這個(gè)階段 可以恢復(fù)用戶數(shù)據(jù),
applicationWillTerminate (應(yīng)用將被終止 ) 應(yīng)用被終止時(shí)調(diào)用該方法并發(fā)生通知, 但內(nèi)存清除時(shí) 除外, 這個(gè)階段釋放一些資源, 也可以保存用戶數(shù)據(jù).
七、控制器的生命周期
創(chuàng)建
1、alloc 創(chuàng)建對(duì)象 分配空間
2、init 初始化對(duì)象 初始化數(shù)據(jù)、
3、loadview 從nib載入視圖
4、viewDidLoad 載入完成 可以自定義數(shù)據(jù)以及動(dòng)態(tài)加載其他數(shù)據(jù)
5、viewWillAppear 視圖即將展示
6、viewDidAppear 視圖加載完成
消失
1、viewWillDisappear 視圖即將消失
2、viewDidDisAppear 視圖已經(jīng)消失
3、delloc 視圖已被銷毀
4.5 frame 和 bounds 有什么不同?
Frame 指的是 該view在父view坐標(biāo)系統(tǒng)中的位置和大小, (參照點(diǎn)是父view的坐標(biāo)系統(tǒng))
Bounds 指的是 該view在本身系統(tǒng)中位置和大小, (參照點(diǎn)是本身坐標(biāo)系統(tǒng))
4.6 聲明可變數(shù)組用copy 修飾會(huì)存在什么問題?
添加, 刪除, 修改 數(shù)組內(nèi)的元素的時(shí)候, 程序會(huì)因找不到對(duì)應(yīng)的方法而崩潰,
因?yàn)?copy 就是將可變數(shù)組復(fù)制成一個(gè) 不可變的數(shù)組對(duì)象.
2.6 關(guān)于 Objective-C 語言的動(dòng)態(tài)性主要體現(xiàn)在哪?
Objective-C 語言的動(dòng)態(tài)性主要體現(xiàn)為3個(gè)方面:
動(dòng)態(tài)類型: 運(yùn)行時(shí)確定對(duì)象的類型
動(dòng)態(tài)綁定: 運(yùn)行時(shí)確定對(duì)象的調(diào)用方法
動(dòng)態(tài)加載: 運(yùn)行時(shí)加載需要的資源或者可執(zhí)行的代碼
擴(kuò)展
NSString *string = [[ NSData alloc ] init ];
問題: string 在編譯時(shí)和運(yùn)行時(shí)分別是什么類型的對(duì)象??
答: 在編譯時(shí)是 NSString 類型
在運(yùn)行時(shí)是 NSData 類型
2.9. id , instancetype 是什么? 區(qū)別是什么?
id : 萬能指針, 能作為參數(shù) 和 方法的返回類型
instancetype : 只能作為方法的返回類型, 并且返回的類型是當(dāng)前定義類的 類類型.
3.1 什么叫多態(tài)?
不同對(duì)象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài).
程序中的多態(tài): 父類指針指向子類對(duì)象
在程序中的表現(xiàn)為: 父類指針指向不同子類對(duì)象的時(shí)候, 通過父類指針調(diào)用被重寫的方法的時(shí)候,. 會(huì)執(zhí)行該指針指向的那個(gè)對(duì)象的方法,
原理: 動(dòng)態(tài)綁定: 動(dòng)態(tài)類型能使程序直到執(zhí)行時(shí)才確定對(duì)象的真是類型, 動(dòng)態(tài)類型綁定能使程序直到程序執(zhí)行時(shí) 才確定要對(duì)那個(gè)對(duì)象調(diào)用的方法.
多態(tài)的條件包括為: 有繼承關(guān)系, 子類重寫父類的方法, 父類指針指向子類對(duì)象.
3.3 什么是編譯時(shí) 與 運(yùn)行時(shí)?
-
編譯時(shí): 即編譯器對(duì)語言的編譯階段, 編譯時(shí)只是對(duì)語言進(jìn)行最基本的檢查報(bào)錯(cuò), 包括詞法分析, 語法分析等等,
將程序代碼翻譯成計(jì)算機(jī)能夠識(shí)別的語言, 編譯通過并不意味著程序就可以成功運(yùn)行, -
運(yùn)行時(shí): 即程序通過了編譯之后, 將編譯好的代碼裝載到內(nèi)存中運(yùn)行起來的階段, 這個(gè)時(shí)候會(huì)具體對(duì)類型進(jìn)行檢查,
而不僅僅是對(duì)代碼的簡單掃描分析. 此時(shí)出錯(cuò)程序會(huì)崩潰.
3.6. isEqual 和 isEqualToString 有什么區(qū)別?
-
isEqual 是比較兩個(gè)NSObject 的方法. 而 isEqualToString 是比較兩個(gè) NSString 的方法.
明顯 isEqualToString只是專門用來比較字符串的. 是isEqual的衍生方法.
-
isEqual 先是比較兩個(gè)指針地址, 如果地址相同直接返回YES,
如果地址不同, 再看兩個(gè)指針指向的對(duì)象是否為空以及對(duì)象類型是否相同,
如果有一個(gè)為空, 或者兩者不是同類對(duì)象, 那么直接返回 NO.
如果都不為空且屬于同類對(duì)象 而且對(duì)象的屬性也相等, 那么返回YES.
3.7. isa 指針指向什么? 有什么作用?
- Objective-C 實(shí)例對(duì)象的isa指針是指向它的類對(duì)象的.
OC 中有3個(gè)層次的對(duì)象: 實(shí)例對(duì)象, 類對(duì)象, 和 元類.
Class 即自定義的類, 是實(shí)例對(duì)象的類對(duì)象, 而類對(duì)象又是其對(duì)應(yīng)元類的實(shí)例對(duì)象.
isa 指針的作用是 通過它可以找到對(duì)應(yīng)類對(duì)象 或 元類中的方法,
例如, 實(shí)例對(duì)象可以在 其類對(duì)象中 找到它的實(shí)例方法,
Class 對(duì)象可以從元類中找到它的類方法.
3.9 . 類別 (category) 和擴(kuò)展 (extension) 的區(qū)別?
類別:
1.類別不能為已存在的類添加實(shí)例變量。
2.類別中添加的方法優(yōu)先級(jí)高,會(huì)覆蓋原類中的方法
3.原類中的私有方法,可以在類別中定義一下,這樣就可以使用了。
4.在categroy中定義的方法可以被子類繼承。
擴(kuò)展:
1.擴(kuò)展中可以定義屬性,變量,和方法
2.擴(kuò)展中定義的屬性和方法不能被子類繼承
3.擴(kuò)展中只能對(duì)自定義的類添加方法,不能對(duì)系統(tǒng)類添加方法。
3.10. 繼承和類別的區(qū)別?
-
繼承可以增加, 修改 或者 刪除方法, 并且可以增加屬性,添加新方法和父類方法一致, 但父類方法仍需要使用.
0. 類別:
1. 系統(tǒng)提供的一些類, 系統(tǒng)本身不提倡繼承, 因?yàn)檫@些類的內(nèi)部實(shí)現(xiàn)對(duì)繼承有所限制.
2. 類別可以將自己構(gòu)建的類中的方法進(jìn)行分組, 對(duì)于大型的類, 提高可維護(hù)性,.
3. 分類的作用:
將類的實(shí)現(xiàn)分散到多個(gè)不同文件 或 多個(gè)不同框架中 創(chuàng)建對(duì)私有方法的前向引用 向?qū)ο筇砑臃钦絽f(xié)議 ( 聲明方法可以不實(shí)現(xiàn), 不調(diào)用只警告. 不報(bào)錯(cuò). ) 正式協(xié)議的優(yōu)點(diǎn): 可繼承. 泛型約束.4. 類別可以在不獲悉 不改變?cè)瓉泶a的情況下往里面添加新的方法.
只能添加. 不能刪除修改, 并且如果類別和原來類中的方法產(chǎn)生名稱沖突, 則類別將覆蓋原來的方法, 因?yàn)轭悇e具有更高的優(yōu)先級(jí).5. 分類的局限性:
無法向類中添加新的實(shí)例變量, 類別沒有位置容納實(shí)例變量 無法添加實(shí)例變量的局限可以使用字典對(duì)象解決
3.11. 在一個(gè)對(duì)象的方法里面. self.name = “ object ” 和 _name = “ object ” 有什么不同?
Self.name = “ object “ 會(huì)調(diào)用對(duì)象的 setName() 方法
_name = “ object ” 會(huì)直接把 object 賦值給當(dāng)前對(duì)象的name 屬性
3.12. 內(nèi)存分區(qū)有哪些? 分別用來存放什么?
代碼區(qū): 存放函數(shù)二進(jìn)制代碼
數(shù)據(jù)區(qū): 系統(tǒng)運(yùn)行時(shí)申請(qǐng)內(nèi)存并初始化, 系統(tǒng)退出時(shí)由系統(tǒng)釋放, 存放全局變量. 靜態(tài)變量. 常量
堆區(qū): 通過 malloc 等函數(shù) 或 new 等動(dòng)態(tài)申請(qǐng)到的, 需手動(dòng)申請(qǐng)和釋放
棧區(qū): 函數(shù)模塊內(nèi)申請(qǐng), 函數(shù)結(jié)束時(shí)由系統(tǒng)自動(dòng)釋放, 存放局部變量, 函數(shù)參數(shù)
3.13. 有哪些設(shè)計(jì)模式? 各自的區(qū)別有哪些?
KVO: 一對(duì)多, 觀察者模式, 鍵值觀察機(jī)制, 提供了觀察某一屬性變化的方法, 極大簡化了代碼
KVC: 鍵值編碼, 一個(gè)對(duì)象在調(diào)用 setValue時(shí)做的事: ( 即KVC 底層實(shí)現(xiàn)原理 )步驟如下:
- 檢查是否存在相應(yīng) key 的 set 方法, 存在就調(diào)用 set 方法
- set 方法不存在時(shí), 就查找 _key 的成員變量 是否存在, 存在就直接賦值
- 如果 _ key 成員變量 沒有找到, 就查找相同名稱的 key. 存在就賦值
- 如果都沒有找到則會(huì)調(diào)用 valueForUndefinedKey和 setValue: forUndefinedKey
delegate : 發(fā)送者和接收者的關(guān)系是直接 . 一對(duì)一的關(guān)系
Notification : 觀察者模式, 發(fā)送者 和接收者的關(guān)系是間接, 多對(duì)多的關(guān)系.
區(qū)別:
1. Delegate 的 效率比 Notification 高
2. Delegate 比 Notification 更直接, 需要關(guān)注返回值, 常帶有 should 關(guān)鍵詞; Notification 不關(guān)心結(jié)果, 常帶有 did 關(guān)鍵詞
兩個(gè)模塊之間的聯(lián)系如果不是很親密, 就用 Notification 傳值, 比如多線程之間的傳值,
3. KVO 容易實(shí)現(xiàn) 兩個(gè)對(duì)象的同步, 比如 Model 和 View 的同步
3.14. 字典的value可為空嗎? OC中表示為空有幾種? 區(qū)別是什么?
NULL : 是宏, 是對(duì)于 C 語言指針而使用的, 表示空指針
nil : 是宏. 是對(duì)于 OC 中的對(duì)象而使用的, 表示對(duì)象為空
Nil : 是宏, 是對(duì)于 OC 中的 類 而使用的, 表示 類 指向空
NSNull : 是類類型, 用于表示空的占位對(duì)象,
字典的value不可直接設(shè)置為空, 會(huì)carsh, 但是可以使用 NSNull 來占位. 例如:
NSDictionary *params = @{ @“arg1” : @“value1”, @“arg2” : value2.isEmpty ? [ NSNull null ] : value2 } ;
3.17. 數(shù)據(jù)存儲(chǔ) 數(shù)據(jù)持久化方式有哪幾種, 有什么區(qū)別?
iOS有4種數(shù)據(jù)持久化:
1.屬性列表 ( plist ) .
2.對(duì)象歸檔 . Sqlite.
3.Core Data
4.NSUserDefaults 用于存儲(chǔ)配置信息
keychain 存儲(chǔ)用戶的敏感信息, 如登錄的token . 需要導(dǎo)入Security 框架
3.18. imageName 和 imageWithContextOfFile 的區(qū)別? 哪個(gè)性能更高?
- imageName的方式加載時(shí), 圖片使用完畢后緩存到內(nèi)存中 內(nèi)存消耗多. 加載速度快, 即使生成的對(duì)象被 內(nèi)存管理池自動(dòng)釋放了. 這份緩存也不會(huì)被釋放, 如果圖像過大, 或者較多. 用這種方式會(huì)消耗很大的內(nèi)存.
imageName 采用了緩存機(jī)制, 如果緩存中已加載了圖片, 直接從緩存讀取,不用每次讀文件. 效率會(huì)更高.
- imageWithContentOfFile 加載 圖片是不會(huì)緩存的,. 加載速度慢
大量使用 imageName方式會(huì)在不需要緩存的地方額外增加開銷 CPU 的時(shí)間, 當(dāng)應(yīng)用程序需要加載一張比較大的圖片并且只使用一次時(shí). 是沒有必要去緩存這個(gè)圖片的.
用imageWithContentOfFile是最為經(jīng)濟(jì)的方式,. 這樣不會(huì)因?yàn)閁IImage元素較多情況下. CPU 會(huì)被逐個(gè)分散 在不必要的緩存上, 浪費(fèi)過多時(shí)間.
3.19 靜態(tài)鏈接是什么? 靜態(tài)庫和動(dòng)態(tài)庫有什么區(qū)別?
靜態(tài)鏈接是指 將多個(gè)目標(biāo)文件合并為一個(gè)可執(zhí)行文件, 直觀感覺就是將所有目標(biāo)文件的段 合并,
靜態(tài)庫, 鏈接時(shí)完整的拷貝至可執(zhí)行文件中, 被多次使用就又多份冗余拷貝
動(dòng)態(tài)庫: 鏈接時(shí)不復(fù)制, 程序運(yùn)行時(shí)由系統(tǒng)動(dòng)態(tài)加載到內(nèi)存, 供程序調(diào)用, 系統(tǒng)只加載一次 多個(gè)程序公用. 節(jié)省內(nèi)存
3.20 Static 和 Const 有什么區(qū)別?
const 是指聲明一個(gè)常量
Static 修飾全局變量時(shí), 表示此全局變量只在當(dāng)前文件可見.
Static 修飾局部變量時(shí), 表示每次調(diào)用的初始值 ,為上一次調(diào)用的值, 調(diào)用結(jié)束后存儲(chǔ)空間不會(huì)釋放.
3.21 深拷貝和淺拷貝的區(qū)別?
深拷貝: 對(duì)一個(gè)對(duì)象進(jìn)行拷貝, 相當(dāng)于對(duì)對(duì)象進(jìn)行復(fù)制, 產(chǎn)生一個(gè)新的對(duì)象, 會(huì)存在兩個(gè)指針分別指向兩個(gè)對(duì)象, 當(dāng)一個(gè)對(duì)象改變或者被銷毀后, 深拷貝出來的新對(duì)象不會(huì)受到影響
淺拷貝: 對(duì)一個(gè)對(duì)象進(jìn)行淺拷貝. 相當(dāng)于對(duì)指向?qū)ο蟮闹羔樳M(jìn)行復(fù)制, 產(chǎn)生一個(gè)新的指針指向這個(gè)對(duì)象, 存在兩個(gè)指針指向同一個(gè)對(duì)象, 對(duì)象銷毀后兩個(gè)指針都應(yīng)該被置空,
總結(jié): 深拷貝 產(chǎn)生了新對(duì)象. 淺拷貝: 本質(zhì)上并沒有產(chǎn)生新對(duì)象.
4.1. UIView 和 CALayer 的關(guān)系和區(qū)別有哪些?
UIView 是 iOS 中所有的界面元素都繼承自它 每一個(gè) UIView 內(nèi)部都默認(rèn)關(guān)聯(lián)著一個(gè)layer 真正的繪圖部分, 是由一個(gè)叫 CALayer 的類來管理的
UIView 有個(gè) layer 屬性 可以返回它的主 CALayer 實(shí)例,
UIView 有一個(gè)layerClass 方法, 返回主layer所使用的類.
UIView 的子類. 可以通過重載這個(gè)方法, 來讓UIView 使用不同的CALayer 來顯示,
** 區(qū)別:
UIView 繼承自UIResponder, 能接收并響應(yīng)事件, 負(fù)責(zé)顯示內(nèi)容的管理,
而CALayer繼承自 NSObject, 不能響應(yīng)事件, 負(fù)責(zé)顯示內(nèi)容的繪制,
UIView 側(cè)重展示內(nèi)容 ,CALayer 側(cè)重于圖形和界面的繪制,
當(dāng) view 展示的時(shí)候, View 是 layer 的CALayerDelegate, view 展示的內(nèi)容是由 CALayer 進(jìn)行 display 的.
View 內(nèi)容的展示 依賴 CALayer 對(duì)內(nèi)容的繪制, UIView 的frame 也是由內(nèi)部的 CALayer 進(jìn)行繪制.
對(duì) UIView 的屬性修改. 不會(huì)引起動(dòng)畫效果. 但是對(duì)于 CALayer 的屬性修改, 是支持默認(rèn)動(dòng)畫效果的, 在 view 執(zhí)行動(dòng)畫的時(shí)候, view 是layer 的代理,
layer 通過 actionForLayer: forKey 向?qū)?yīng)的代理 view 請(qǐng)求動(dòng)畫 action.
每個(gè)UIView 內(nèi)部都有一個(gè) CALayer 在背后提供內(nèi)容的繪制和顯示, 并且 UIView 的尺寸樣式都由內(nèi)部的 layer 所提供, layer 比 view 多了個(gè) anchorPoint
一個(gè) CALayer 的 frame 是由其 anchorPoint position bounds. Transfrom 共同決定的, 而 UIView 的 frame 只是簡單的返回 CALayer 的frame,
4.2. layoutSubView 和 drawRects 區(qū)別?
layoutSubView 在以下情況會(huì)被調(diào)用:
1. init 初始化不會(huì)觸發(fā) layoutSubView
2. addSubView會(huì)觸發(fā)layoutSubView
3. 設(shè)置 view 的Frame 會(huì)觸發(fā) layoutSubview . 當(dāng)然前提是 frame 的值設(shè)置前后發(fā)生了變化.
4. 滾動(dòng)一個(gè) UIScrollView 會(huì)觸發(fā) layoutSubView
5. 旋轉(zhuǎn) Screen 會(huì)觸發(fā)父View上的 layoutSubView事件.
6. 改變一個(gè) UIView 大小的時(shí)候.也會(huì)觸發(fā)父 UIView 上的 layoutSubView 事件
7. 直接調(diào)用 setLayoutSubView
drawRect 在以下情況會(huì)被調(diào)用:
1.如果 在 UIView 初始化時(shí)沒有設(shè)置 rect 大小, 將導(dǎo)致 drawRect 不被自動(dòng)調(diào)用,
2.drawRect 調(diào)用是在 Controller —-> loadView. Controller —-> viewDidLoad 兩方法之后調(diào)用.
3.在調(diào)用 sizeToFit 后被調(diào)用. 所以可以先調(diào)用 sizeToFit 計(jì)算出 size . 然后系統(tǒng)自動(dòng)調(diào)用 drawRect 方法.
4.通過設(shè)置 contentMode 屬性值 為 UIViewContentModeRedraw. 那么每次設(shè)置 或更改 frame 的時(shí)候 自動(dòng)調(diào)用 drawRect.
5.直接調(diào)用 setNeedsDisplay 或者 setNeedsDisPlayInRect 觸發(fā) drawRect. 但是有個(gè)前提條件是 rect 不能為0.
drawRect 方法使用注意點(diǎn):
1> 若使用 UIView 繪圖, 只能在 drawRect 方法中獲取相應(yīng)的contextRef 并繪圖,
如果在其他方法中獲取將獲取到一個(gè) invalidate 的 ref 并且不能用于畫圖, drawRect 方法不能手動(dòng)顯示調(diào)用,
必須通過 setNeedsDisplay 或者 setNeedsDisplayInRect ,. 讓系統(tǒng)自動(dòng)調(diào)用該方法.
2> 若使用 calayer 繪圖, 只能在 drawInContext 中 繪制, 或者在 delegate 中的相應(yīng)方法繪制, 同樣也是調(diào)用 setNeedDisplay 等間接調(diào)用以上方法.
3> 若要實(shí)時(shí)畫圖, 不能使用 gestureRecognizer 只能使用 touchbegan 等方法來調(diào)用 setNeedsDisplay 實(shí)時(shí)刷新屏幕.
4.3 哪些操作會(huì)出發(fā)離屏渲染?
光柵化 layer. shouldRasterize = YES
遮罩. layer. mask
圓角. 同時(shí)設(shè)置, layer.maskToBounds = yes layer.cornerRadis 大于 0
陰影. layer.shadow 如果設(shè)置了 layer. shadowPath 就不會(huì)產(chǎn)生離屏渲染.
4.7 聲明一個(gè) NSString 或 NSArray 使用 Strong 修飾 可能會(huì)造成什么問題?
父類指針可以指向子類對(duì)象, 使用 Copy 修飾的目的是為了讓該對(duì)象的屬性不受外界影響,
使用Strong修飾可能使這個(gè)屬性指向一個(gè)可變對(duì)象, 如果這個(gè)可變對(duì)象在外部被修改了. 那么會(huì)影響到該屬性.
4.8 retain 和 copy 的區(qū)別?
copy 是建立了一個(gè)相同的對(duì)象, 而 retain 不是.
retain: 是指針拷貝, copy 是內(nèi)容拷貝,
retain: 是創(chuàng)建一個(gè)指針, copy 是創(chuàng)建一個(gè)新的對(duì)象,
copy : 建立一個(gè)索引計(jì)數(shù) 為 1 的新對(duì)象, 然后釋放舊對(duì)象, 新的對(duì)象 retain 為1, 與舊有對(duì)象引用計(jì)數(shù) 無關(guān), 減少了對(duì)象對(duì)上下文的依賴.
retain: 釋放舊的對(duì)象, 將舊對(duì)象的值賦予輸入給新對(duì)象, 再提高輸入對(duì)象的索引計(jì)數(shù) 為 1, 新對(duì)象和舊對(duì)象的指針相同.
4.9 readwrite readonly assign retain copy weak strong nonatomic 屬性的作用? 即聲明屬性時(shí)可修飾屬性特性的修飾詞作用?
1.getter = getterName , setter = setterName 設(shè)置 getter 和 setter的方法名
2.readwrite, readonly : 設(shè)置屬性可訪問級(jí)別, readwrite 可讀可寫, readonly 可讀不可寫
3.assign: setter方法直接賦值, 不會(huì)進(jìn)行任何retain操作, 用于非指針變量, 一般用于修飾基礎(chǔ)數(shù)據(jù)類型 和 C 數(shù)據(jù)類型,
4.retain : setter 方法對(duì)參數(shù)進(jìn)行release舊值在retain新值,
5.copy : setter 方法對(duì)參數(shù)進(jìn)行copy 操作, 和 retain處理流程一樣, 先舊值 release, 再 Copy 出新的對(duì)象, retainCount 為1.
6.nonatomic , atomic: 非原子操作 和 原子操作, 非原子操作是線程不安全的, 但在多線程并發(fā)訪問時(shí)會(huì)提高性能, 原子操作是線程安全的, 但不是決定的, 性能比非原子操作低. 一般使用nonatomic
7.weak : 用于指針變量, 比 assign 多了一個(gè)功能, 當(dāng)對(duì)象消失后自動(dòng)把指針置為nil, 可以避免循環(huán)引用.
8.strong : 用于指針變量, setter方法對(duì)參數(shù)進(jìn)行release 舊值再retain新值, 屬于強(qiáng)引用
4.10. OC堆和棧的區(qū)別?
管理方式: 對(duì)于棧而言, 是由編譯器自動(dòng)管理, 無需手動(dòng)控制,
對(duì)于堆而言, 釋放工作需要程序猿控制, 容易造成內(nèi)存泄漏.
分配方式: 堆都是動(dòng)態(tài)分配的, 沒有靜態(tài)分配的堆,
棧有兩種分配方式, 靜態(tài)分配和動(dòng)態(tài)分配, 靜態(tài)分配是由編譯器完成的, 比如 局部變量的分配, 動(dòng)態(tài)分配由 alloca 函數(shù)進(jìn)行分配, 但是棧的動(dòng)態(tài)分配和堆是不同的, 他的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放, 無需手動(dòng)實(shí)現(xiàn),
空間分配的區(qū)別:
棧: 由操作系統(tǒng)自動(dòng)分配釋放, 存放函數(shù)的參數(shù)值, 局部變量的值等, 使用的是一級(jí)緩存, 通常都是被調(diào)用時(shí)處于存儲(chǔ)空間中, 調(diào)用完畢立即釋放.
堆: 一般由程序猿手動(dòng)釋放, 若不釋放, 程序結(jié)束時(shí)可能由OS 回收, 存放在二級(jí)緩存, 生命周期由虛擬機(jī)的垃圾回收算法來決定,
4.13. 用assign 修飾對(duì)象會(huì)怎么樣?
如果用assign修飾一個(gè)對(duì)象后,當(dāng)對(duì)象被釋放后,存在于棧上的指針還是存在的,
假如此時(shí)使用指針,它就是一個(gè)野指針了,就容易造成程序崩潰,如果是用weak修飾的對(duì)象,則不會(huì)產(chǎn)生上面的情況,
因?yàn)閷?duì)象銷毀的時(shí)候,系統(tǒng)會(huì)將指針置nil,也就不會(huì)產(chǎn)生野指針了。
所以: 修飾對(duì)象用 weak, 基礎(chǔ)數(shù)據(jù)類型用 assgin
4.14 PerformSelector 的實(shí)現(xiàn)原理
1. 當(dāng)調(diào)用 NSObject 的 performSelecter:afterDelay: 后,實(shí)際上其內(nèi)部會(huì)創(chuàng)建一個(gè) Timer 并添加到當(dāng)前線程的 RunLoop 中。所以如果當(dāng)前線程沒有 RunLoop,則這個(gè)方法會(huì)失效。
2. 當(dāng)調(diào)用 performSelector:onThread: 時(shí),實(shí)際上其會(huì)創(chuàng)建一個(gè) Timer 加到對(duì)應(yīng)的線程去,同樣的,如果對(duì)應(yīng)線程沒有 RunLoop 該方法也會(huì)失效。
4.15 @ property 會(huì)自動(dòng)幫我們做的事有哪些?
1. 生成一個(gè)帶下劃線的成員變量
2. 聲明一個(gè) set 方法. 一個(gè) get 方法
3. 生成 set 方法 和 get 方法的具體實(shí)現(xiàn).
4.16 什么是垂懸指針? 什么是野指針?
垂懸指針: 指針指向的內(nèi)存已經(jīng)被釋放了. 但是指針還在, 這就是一個(gè)垂懸指針, 或者說是迷途指針
野指針: 沒有進(jìn)行初始化的指針, 其實(shí)都是野指針.
4.17 實(shí)例方法和類方法有什么本質(zhì)區(qū)別和聯(lián)系?
類方法:
1.類方法是屬于類對(duì)象的
2.類方法只能通過類對(duì)象調(diào)用
3.類方法中的self是類對(duì)象
4.類方法可以調(diào)用其他的類方法
5.類方法中不能訪問成員變量
6.類方法中不能直接調(diào)用對(duì)象方法
實(shí)例方法:
1.實(shí)例方法是屬于實(shí)例對(duì)象的
2.實(shí)例方法只能通過實(shí)例對(duì)象調(diào)用
3.實(shí)例方法中的self是實(shí)例對(duì)象
4.實(shí)例方法中可以訪問成員變量
5.實(shí)例方法中直接調(diào)用實(shí)例方法
6.實(shí)例方法中也可以調(diào)用類方法(通過類名)
4.19 為什么一定要在主線程里面更新UI?
像UIKit這樣大的框架上確保線程安全是一個(gè)重大的任務(wù),會(huì)帶來巨大的成本。
UIKit不是線程安全的,假如在兩個(gè)線程中設(shè)置了同一張背景圖片,很有可能就會(huì)由于背景圖片被釋放兩次,使得程序崩潰。
或者某一個(gè)線程中遍歷找尋某個(gè)subView,然而在另一個(gè)線程中刪除了該subView,那么就會(huì)造成錯(cuò)亂。
apple有對(duì)大部分的繪圖方法和諸如UIColor等類改寫成線程安全可用,可還是建議將UI操作保證在主線程中
5.5. 線程間通信
1> NSThread 調(diào)用系統(tǒng)的 performSelectorOnMainThread 回到主線程處理UI或其他事件. performSelector:(SEL)aSelector 回到指定線程處理事件
2> GCD: 子線程與主線程通過系統(tǒng)方法 dispatch_async(dispath_get_main_queue( ) ) 進(jìn)行線程間通信
3> NSOperation : 設(shè)置依賴關(guān)系 手動(dòng)調(diào)用主線程[NSOperationQueue mainQueue] 進(jìn)行線程間通信
5.6. 用過NSOperationQueue嗎?如果用過或者了解的話,為什么要使用 NSOperationQueue?實(shí)現(xiàn)了什么?簡述它和GCD的區(qū)別和類似的地方(提示:可以從兩者的實(shí)現(xiàn)機(jī)制和適用范圍來述)
使用NSOperationQueue 用來管理子類化的NSOperation 對(duì)象. 可以控制其線程并發(fā)數(shù)目.
GCD 和 NSOperation 都可以實(shí)現(xiàn)對(duì)線程的管理.
區(qū)別是 NSOperation 和 NSOperationQueue 是多線程的 面向?qū)ο蟪橄?
項(xiàng)目中使用 NSOperation的優(yōu)點(diǎn)是對(duì)線程的高度抽象,會(huì)使得項(xiàng)目的程序結(jié)構(gòu)更好,
子類化NSOperation是具有面向?qū)ο蟮膬?yōu)點(diǎn), 復(fù)用 和 封裝
使得實(shí)現(xiàn)是多線程支持, 接口簡單, 適合在復(fù)雜的項(xiàng)目中使用,
GCD的優(yōu)點(diǎn)是 本身非常簡單, 易用, 對(duì)于不復(fù)雜的多線程操作, 會(huì)節(jié)省代碼量, 而Block參數(shù)的使用, 使代碼更為易讀, 適合在簡單項(xiàng)目中使用,
GCD是純C語言的API. NSOperationQueue 是基于GCD的 OC 版本的封裝
GCD只支持 FIFO 隊(duì)列, 即先入先出, NSOperationQueue 可以調(diào)整執(zhí)行順序, 設(shè)置最大并發(fā)數(shù)量, 可以在Operation 間設(shè)置依賴關(guān)系,
而GCD需要寫很多代碼才能實(shí)現(xiàn)依賴.
NSOperationQueue 支持KVO 可以檢測operation 是否正在執(zhí)行, 是否結(jié)束, 是否取消,
GCD的執(zhí)行速度比NSOperationQueue快. 任務(wù)間不太互相依賴,
5.7. NSOperation. GCD. NSThread 的區(qū)別?
NSOperation 與 GCD 的區(qū)別:
GCD:
GCD 純C
GCD 是將任務(wù)添加到隊(duì)列 *( 隊(duì)列有 串行 并行 全局 主隊(duì)列 ) 并且以 同步 或 異步的方式執(zhí)行任務(wù)函數(shù)
GCD提供NSOperation 不具備的功能有以下:
一次性執(zhí)行
延遲執(zhí)行
調(diào)度組
GCD 是嚴(yán)格的隊(duì)列. 先進(jìn)先出. FIFO
NSOperation:
NSOperation 在 iOS 2.0 推出. 4.0 重寫
NSOperation 將操作 ( 異步任務(wù) )添加到隊(duì)列 ( 并發(fā)隊(duì)列 ) 就會(huì)執(zhí)行指定的函數(shù)
NSOperation 提供的方便操作有以下:
最大并發(fā)數(shù)
隊(duì)列暫停和繼續(xù)
取消所有的操作
指定操作之間的依賴關(guān)系. 可以讓異步任務(wù)同步執(zhí)行
可以利用KVO監(jiān)聽一個(gè)任務(wù)是否完成
可以設(shè)置任務(wù)的優(yōu)先級(jí), 能使同一個(gè)并行隊(duì)列中的任務(wù)區(qū)分先后地執(zhí)行
對(duì)NSOperation 繼承, 在這之上添加成員變量和成員方法, 提高代碼的復(fù)用度
GCD 與 NSThread 的區(qū)別:
NSThread 使用 @selector 指定要執(zhí)行的方法. 代碼分散
GCD通過 block 指定執(zhí)行的方法, 代碼集中
GCD 不用管理線程的生命周期 ( 創(chuàng)建 銷毀 復(fù)用 )
如果要開多個(gè)線程 NSThread 必須實(shí)例化多個(gè)線程對(duì)象
NSThread 通過 performSelector 方法實(shí)現(xiàn)線程間通信
為什么要取消和恢復(fù)隊(duì)列?
一般內(nèi)存警告后 取消隊(duì)列中的操作
為保證ScrollView 在滾動(dòng)時(shí)候的流暢, 通常在滾動(dòng)開始時(shí), 暫停隊(duì)列中的所有操作, 滾動(dòng)結(jié)束后, 恢復(fù)操作.
5.9 什么是異步繪制?
異步繪制 就是可以在子線程把需要繪制的圖形, 提前在子線程處理好,
將準(zhǔn)備好的圖像數(shù)據(jù)直接返給主線程使用, 這樣可以降低主線程的壓力.
5.11 例舉下你所知道的線程同步策略?
1. OSSpinLock 自旋鎖, 已不再安全, 除這個(gè)鎖, 下列鎖在等待時(shí), 都會(huì)進(jìn)入線程休眠狀態(tài), 而非忙等.
2. os_unfair_lock atomic就是使用此鎖來保證原子性的.
3. pthread_mutex_t 互斥鎖. 并且支持遞歸實(shí)現(xiàn)和條件實(shí)現(xiàn),
4. NSLock, NSRecursiveLock. 基本的互斥鎖. 后者支持遞歸調(diào)用, 都是對(duì) pthread_mutex_t 的封裝.
5. NSCondition. NSConditionLock. 條件鎖. 對(duì)pthread_mutex_t 的封裝,
6. dispatch_semaphore_t 信號(hào)量.
7. @synchronized 也是對(duì) pthread_mutex_t 的封裝.
5.12 Runtime 如何實(shí)現(xiàn) weak 變量的自動(dòng)置為nil 功能?
Runtime 在注冊(cè)和初始化一個(gè)類時(shí). 當(dāng)一個(gè)屬性被修飾為 weak 時(shí), 會(huì)將 weak 變量指向的地址作為 Value 放入一張 hash 表中.
將 weak變量的值 作為key. 這樣形成一個(gè) key - value 的鍵值對(duì).
當(dāng)引用計(jì)數(shù)變?yōu)?0 的時(shí)候. 系統(tǒng)通過 key - value 查找指向weak 變量的地址,. 將變量賦值為 nil.
5.13 atomic 的實(shí)現(xiàn)機(jī)制是怎樣的? 為什么不能保證絕對(duì)的線程安全?
atomic 是在setter和getter方法里會(huì)使用自旋鎖 spinlock_t 來保證setter 和 getter方法的線程安全, 可以看做是 getter方法獲取到返回值之前不會(huì)執(zhí)行setter方法里的賦值代碼,
如果不加 atomic. 可能在getter方法讀取的過程中, 在別的線程已經(jīng)發(fā)生setter操作, 從而出現(xiàn)異常值,
atomic 不能絕對(duì)的保證線程安全, 因?yàn)槌隽薵etter和setter方法后就不能繼續(xù)保證線程安全
5.14 RunLoop 的作用是什么?
字面意思是 消息循環(huán), 運(yùn)行循環(huán), runloop內(nèi)部實(shí)際上就是一個(gè) do-while循環(huán), 它在循環(huán)監(jiān)聽各種事件源, 消息, 對(duì)他們進(jìn)行管理并分發(fā)給線程來執(zhí)行. 主要作用有:
1.通知觀察者將要進(jìn)入運(yùn)行循環(huán), 線程和RunLoop之間是一一對(duì)應(yīng)的.
2.通知觀察者將要處理計(jì)時(shí)器
3.通知觀察者任何非基于端口的輸入源即將被觸發(fā).
4.觸發(fā)任何準(zhǔn)備觸發(fā)的基于非端口的輸入源
5.如果基于端口的輸入源準(zhǔn)備就緒并等待觸發(fā), 請(qǐng)立即處理該事件, 轉(zhuǎn)到第9步
6.通知觀察者線程即將睡眠
7.將線程置于睡眠狀態(tài), 直到發(fā)生以下事件之一:
事件到達(dá)基于端口的輸入源
計(jì)時(shí)器運(yùn)行
為運(yùn)行循環(huán)設(shè)置的超時(shí)值到期
運(yùn)行循環(huán)被明確喚醒
8. 通知觀察者線程被喚醒
9. 處理待處理事件
- 如果觸發(fā)了用戶定義的計(jì)時(shí)器, 則主力計(jì)時(shí)器事件并重新啟動(dòng)循環(huán), 轉(zhuǎn)到第二步,
- 如果輸入源被觸發(fā), 則傳遞事件,
- 如果運(yùn)行循環(huán)被明確喚醒但尚未超時(shí), 請(qǐng)重新啟動(dòng)循環(huán). 轉(zhuǎn)到第二步.
10. 通知觀察者運(yùn)行循環(huán)已退出.
6.2. SDWebImage 底層原理?
1.SDWebImageManager 根據(jù)URL 開始處理圖片
2.先根據(jù)URL作為下標(biāo)從緩存查找圖片是否已經(jīng)下載.
3.如果本地緩存圖片中有圖片, SDImageCacheDelegate 直接調(diào)用圖片顯示.
4.如果本地緩存中沒有, 則開始通過URL為key 從本地磁盤查找圖片是否已經(jīng)被緩存至硬盤.
5.本地磁盤如果存在圖片, 則通過 SDWebImageManagerDelegate 到 UIImageView+WebCache 展示圖片
6.如果本地磁盤不存在圖片, 說明所有緩存都不存在該圖片, 需要下載,
7.生成下載器 SDWebImageDownloader 開始向服務(wù)器請(qǐng)求下載,
8.圖片下載由 NSURLConnection 來做,實(shí)現(xiàn)相關(guān) delegate 來判斷圖片下載中、下載完成和下載失敗。
9.數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。
10.通知所有的 downloadDelegates 下載完成,回調(diào)給需要的地方展示圖片。
11.將圖片以URL為下標(biāo) . 保存到 SDImageCache 中,內(nèi)
SDImageCache 分為兩個(gè)部分:一個(gè)是內(nèi)存層面的,一個(gè)是硬盤層面的。
內(nèi)存層面的相當(dāng)是個(gè)緩存器. 以Key-Value的形式存儲(chǔ)圖片。當(dāng)內(nèi)存不夠的時(shí)候會(huì)清除所有緩存圖片。
用搜索文件系統(tǒng)的方式做管理,文件替換方式是以時(shí)間為單位,剔除時(shí)間大于一周的圖片文件。
當(dāng)SDWebImageManager 向 SDImageCache要資源時(shí),先搜索內(nèi)存層面的數(shù)據(jù),如果有直接返回,沒有的話去訪問磁盤,
將圖片從磁盤讀取出來,然后做Decoder,將圖片對(duì)象放到內(nèi)存層面做備份,再返回調(diào)用層。存緩存和硬盤緩存同時(shí)保存。
7.2. UITableView 的優(yōu)化
1、注冊(cè)重用標(biāo)識(shí)符
2.避免cell的重新布局
3.提前計(jì)算并緩存cell的屬性及內(nèi)容
4.減少cell中控件的數(shù)量
5.不要使用ClearColor,無背景色,透明度也不要設(shè)置為0因?yàn)殇秩竞臅r(shí)比較長
6.使用局部更新 如果只是更新某組的話,使用reloadSection進(jìn)行局部更
7.加載網(wǎng)絡(luò)數(shù)據(jù),下載圖片,使用異步加載,并緩存
8.少使用addView 給cell動(dòng)態(tài)添加view
9.按需加載cell,cell滾動(dòng)很快時(shí),只加載范圍內(nèi)的cell
10.不要實(shí)現(xiàn)無用的代理方法,tableView只遵守兩個(gè)協(xié)議
11.不要做多余的繪制工作。
12.使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)。減少不必要的修改
7.3 如何對(duì)代碼進(jìn)行 性能優(yōu)化?
1. 利用性能分析工具檢測. 包括靜態(tài) Analyze 工具 , 以及運(yùn)行時(shí) profile 工具, 通過Xcode工具欄中 Product —> Profile 可以啟動(dòng).
2. 測試程序的啟動(dòng)時(shí)間, 點(diǎn)擊 Time Prefiler 應(yīng)用程序開始運(yùn)行后, 就能獲取整個(gè)應(yīng)用程序運(yùn)行消耗時(shí)間分布 和 百分比,
為了保證數(shù)據(jù)分析在統(tǒng)一使用場景的真實(shí). 要注意一定要使用真機(jī). 模擬器此時(shí)是運(yùn)行在 MAC 上. 而 Mac 上的 cpu 往往比 iOS 設(shè)備快.
3. 為防止一個(gè)應(yīng)用占用過多的系統(tǒng)資源, 工程師設(shè)計(jì)了一個(gè) “看門狗”機(jī)制. 在不同場景下, 看門狗 會(huì)檢測應(yīng)用的性能,
如果超出了該場景所規(guī)定的運(yùn)行時(shí)間, 看門狗 就會(huì)強(qiáng)制終結(jié)這個(gè)應(yīng)用的進(jìn)程, 開發(fā)者在 crashlog 里面. 會(huì)看到如: 0x8badf00d 這樣的錯(cuò)誤代碼.
8.0 網(wǎng)絡(luò)相關(guān)
8.1. TCP 和 UDP的區(qū)別
TCP: 傳輸控制協(xié)議, 提供的是面向連接 可靠的字節(jié)流服務(wù). 客戶端和服務(wù)端在交換數(shù)據(jù)之前, 必須先在雙方建立一個(gè) TCP 連接, 一個(gè)TCP 連接必須經(jīng)過三次握手才能建立.
TCP 提供 超時(shí)重發(fā), 丟棄重復(fù)數(shù)據(jù), 檢驗(yàn)數(shù)據(jù), 流量控制等功能, 保證數(shù)據(jù)能從一端 傳到另一端.
UDP: 用戶數(shù)據(jù)報(bào)協(xié)議, 是面向數(shù)據(jù)報(bào)的運(yùn)輸層協(xié)議.
UDP 是面向 非連接的協(xié)議, 它不與對(duì)方建立連接, 而是只負(fù)責(zé)把數(shù)據(jù)包發(fā)送過去, 不提供可靠性, 可靠性不高,
由于不需要在客戶端與服務(wù)端建立連接, 并且沒有超時(shí)重發(fā)等機(jī)制, 因此傳輸速度 很快.
差別在于:
tcp —- 面向連接 udp —- 面向非連接
Tcp —- 傳輸可靠 udp —- 傳輸不可靠
tcp —- 傳輸大量數(shù)據(jù) udp ——傳輸少量數(shù)據(jù)
tcp —— 速度慢 udp —— 速度快
8.2. Socket 和 http 連接的區(qū)別
socket 連接 和 http 連接的區(qū)別:
http 是基于socket 之上的, socket 是一套完整的 tcp udp 協(xié)議的接口
HTTP 協(xié)議: 簡單對(duì)象訪問協(xié)議, 對(duì)應(yīng)于應(yīng)用層, HTTP 協(xié)議是基于 TCP連接的.
TCP 協(xié)議: 對(duì)應(yīng)于傳輸層
IP 協(xié)議: 對(duì)應(yīng)于網(wǎng)絡(luò)層
TCP/IP 是傳輸層協(xié)議, 主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸, 而 HTTP 是應(yīng)用層協(xié)議, 主要解決如何包裝數(shù)據(jù),
Socket 是對(duì) TCP/IP協(xié)議的封裝, Socket 本身并不是協(xié)議, 而是一個(gè)調(diào)用接口, 通過Socket 我們才能使用TCP/IP 協(xié)議.
HTTP 連接: 短連接, 即客戶端向服務(wù)端發(fā)送一次請(qǐng)求, 服務(wù)端響應(yīng)后連接, 請(qǐng)求結(jié)束后, 會(huì)主動(dòng)釋放連接.
Socket連接: 長連接, 理論上客戶端和服務(wù)端一旦建立連接將不會(huì)主動(dòng)斷掉. 但由于各種因素可能會(huì)斷開.
例如: 服務(wù)端或客戶端主機(jī)掛掉了. 網(wǎng)絡(luò)故障, 或兩者之間長時(shí)間沒有數(shù)據(jù)傳輸, 網(wǎng)絡(luò)防火墻可能會(huì)斷開該連接以釋放網(wǎng)絡(luò)資源,
所以當(dāng)一個(gè) Socket 連接中沒有數(shù)據(jù)的傳輸, 為了 維持連接 需要發(fā)送 心跳包.
一、scoket 相關(guān)知識(shí)點(diǎn)(概念、三次握手四次斷開、心跳包、重連以及重連次數(shù))
Scoket 是客戶端和服務(wù)端之間相互通信的橋梁,想要實(shí)現(xiàn)兩者之間的通訊,就必須建立連接俗稱三次握手。
第一次、由客戶端向服務(wù)端發(fā)送 SYN 同步報(bào)文。
第二次、當(dāng)服務(wù)端收到 SYN 同步報(bào)文之后,會(huì)返回給客戶端 SYN 同步報(bào)文和 ACK 確認(rèn)報(bào)文。
第三次、客戶端會(huì)向服務(wù)端發(fā)送 ACK 確認(rèn)報(bào)文,此時(shí)客戶端和服務(wù)端的連接正式建立。
建立連接之后為保證兩端時(shí)刻活躍,客戶端需要每隔一段時(shí)間向服務(wù)端發(fā)送心跳包
有時(shí)由于網(wǎng)絡(luò)波動(dòng)或則其他一些因素導(dǎo)致兩者斷開了連接,我們需要做重連處理,一般情況重連時(shí)間2的指數(shù)級(jí)增長當(dāng)達(dá)到一定次數(shù)將放棄重連。
注:SYN 同步序列編號(hào)(Synchronize Sequence Numbers)。是TCP/IP建立連接時(shí)使用的握手信號(hào)。
二、MQTT相關(guān)知識(shí)點(diǎn)(概念、訂閱、發(fā)布、心跳包、重連)
消息隊(duì)列遙測傳輸簡稱MQTT,他是發(fā)布/訂閱型消息協(xié)議,MQTT協(xié)議具有輕量、簡單、開放和易于實(shí)現(xiàn)等優(yōu)點(diǎn)因此它適用范圍非常廣泛。
MQTT協(xié)議有三種身份:發(fā)布者、代理、訂閱者,發(fā)布者和訂閱者都為客戶端,代理為服務(wù)器,同時(shí)消息的發(fā)布者也可以是訂閱者。
MQTT訂閱
傳輸?shù)南⒎譃橹黝}(Topic,可理解為消息的類型)和負(fù)載(可以理解為消息的內(nèi)容)兩部分
通過消息的內(nèi)容我們可以得到是否訂閱成功,訂閱失敗需要重新訂閱,一般我們也會(huì)設(shè)置一個(gè)最大訂閱次數(shù),
MQTT發(fā)布
發(fā)布消息會(huì)攜帶主題(topic)和消息內(nèi)容,我們接收到MQTT發(fā)布topic之后根據(jù)topic來做相應(yīng)的處理
8.3. AFN 是如何實(shí)現(xiàn)斷點(diǎn)續(xù)傳的??
1.檢查服務(wù)端文件信息
2.檢查本地文件
3.如果本地文件比服務(wù)端文件小, 斷點(diǎn)續(xù)傳, 利用 HTTP 請(qǐng)求頭的 Range 實(shí)現(xiàn)斷點(diǎn)續(xù)傳
4.如果比服務(wù)端文件大, 說明本地文件錯(cuò)誤, 重新請(qǐng)求下載
5.如果和服務(wù)端文件一樣, 下載完成
AFN 默認(rèn)超時(shí) 時(shí)間 為 60s
8.4 項(xiàng)目中網(wǎng)絡(luò)層如何做安全處理?
盡量使用 https
不要傳輸明文密碼
-
post 并不比 get 安全 事實(shí)上, post 和 get 一樣不安全, 都是明文 參數(shù)放在 queryString 或者 body 沒有任何安全上的差別,
在http的環(huán)境下. 使用post 或者 get 都需要做加密和簽名處理.
8.5 HTTPS 協(xié)議 與 HTTP 協(xié)議有什么區(qū)別與聯(lián)系?
HTTPS 協(xié)議是由 SSL + HTTP 協(xié)議構(gòu)建的可進(jìn)行加密傳輸身份認(rèn)證的網(wǎng)絡(luò)協(xié)議. 要比 http協(xié)議安全.
HTTPS 安全超文本傳輸協(xié)議 . 它是一個(gè)安全通信通道. 基于 HTTP 開發(fā). 用于在 客戶計(jì)算機(jī) 和服務(wù)器之間交換信息,.
它使用安全套接字層 ( SSL ) 進(jìn)行信息交換, 簡單來說 它是 HTTP 的安全版,
區(qū)別在于:
https協(xié)議需要用到 ca 申請(qǐng)證書, 一般需要交費(fèi).
http 是超文本傳輸協(xié)議, 信息是明文傳輸, https 則是具有安全性的 SSL 加密傳輸協(xié)議
http 和 https 使用的是完全不同的連接方式, 用的端口也不一樣. http 是 80 . Https 是443
http 的連接很簡單. 無狀態(tài).
十一、 HTTP協(xié)議中 POST 方法和 GET 方法有那些區(qū)別?
GET用于向服務(wù)器請(qǐng)求數(shù)據(jù),POST用于提交數(shù)據(jù)
GET請(qǐng)求,請(qǐng)求參數(shù)拼接形式暴露在地址欄,而POST請(qǐng)求參數(shù)則放在請(qǐng)求體里面,因此GET請(qǐng)求不適合用于驗(yàn)證密碼等操作
GET請(qǐng)求的URL有長度限制,POST請(qǐng)求不會(huì)有長度限制
1.6 設(shè)計(jì)模式的工廠方法?
工廠模式是利用了 面向?qū)ο?大特性之一 ---> 多態(tài).
父類指針指向子類對(duì)象這個(gè)特性,
父類定義方法, 子類實(shí)現(xiàn), 是一種創(chuàng)建類模式,
在任何需要生產(chǎn)復(fù)雜對(duì)象的地方, 都可以使用工廠方法,
良好的封裝性, 代碼結(jié)構(gòu)清晰. 屏蔽產(chǎn)品類, 調(diào)用者只需要關(guān)心產(chǎn)品的接口 而不關(guān)心內(nèi)部的實(shí)現(xiàn),
復(fù)雜對(duì)象比較適合工廠模式. 簡單對(duì)象有時(shí)僅需要 new 創(chuàng)建就可以了.
工廠模式依賴抽象架構(gòu), 它把實(shí)例化任務(wù)交給實(shí)現(xiàn)類. 擴(kuò)展性較好.
1.2 什么是響應(yīng)者鏈?
響應(yīng)者鏈用于確定事件響應(yīng)者的一種機(jī)制, 其中的事件主要指 觸摸事件.
響應(yīng)觸摸事件的都是屏幕上的界面元素, 而且必須是繼承自 UIResponse 類的界面類. 才可以響應(yīng)觸摸事件.
一個(gè)事件響應(yīng)者的完成 主要經(jīng)過兩個(gè)過程, hitTest 方法命中視圖 和相應(yīng)這鏈 確定相應(yīng)者,
hitTest 方法首先從頂部 UIApplication 往下調(diào)用, ( 從父類到子類. ) 直到找到命中者, 然后從命中者視圖 沿著 相應(yīng)者鏈 往上傳遞尋找真正的相應(yīng)者 ,
一個(gè)繼承自 UIResponder 的視圖 要想能響應(yīng)事件, 需要滿足以下條件:
1. 必須要有對(duì)應(yīng)的視圖控制器, 即響應(yīng)函數(shù)的邏輯代碼要寫在控制器內(nèi), 另外,(對(duì)于不支持默認(rèn)能響應(yīng)事件的控件 如” UIImageView ) userInteractionEnabled 屬性必須設(shè)置為 YES , 否則會(huì)忽視事件不響應(yīng).
2. hidden 屬性必須為NO, 隱藏的視圖不可以響應(yīng)事件, alpha 透明度屬性的值不能過低,. 低于 0.01 接近透明也會(huì)因影響響應(yīng).
3. 需要注意保證樹形結(jié)構(gòu)的正確性. 子節(jié)點(diǎn)的 frame 一定都要在 父節(jié)點(diǎn)的 frame 內(nèi)
3.16. 簡要說明 APP的啟動(dòng)過程, 從main 文件說起. Main 函數(shù)中有什么? 作用是什么?
打開程序 —> 執(zhí)行main 函數(shù). —-> UIApplicatonMain 函數(shù). ——-> 初始化 UIApplicationMain 函數(shù) (包括 設(shè)置代理, 開啟事件循環(huán) ) —— > 監(jiān)聽系統(tǒng)事件 —— > 程序啟動(dòng)結(jié)束
UIApplicationMain 函數(shù)作用:
1> 根據(jù)傳入的第三個(gè)參數(shù) 創(chuàng)建 UIApplication 對(duì)象 或它的子類對(duì)象, 如果該參數(shù)為nil,. 直接使用該UIApplication對(duì)象的 代理 屬性,
2> 根據(jù)傳入的第四個(gè)參數(shù) 創(chuàng)建 AppDelegate 對(duì)象, 并將該對(duì)象賦值給第一步 創(chuàng)建的 UIApplication 對(duì)象的 delegate 屬性.
3> 開啟一個(gè)事件循環(huán). 循環(huán)監(jiān)控應(yīng)用程序發(fā)生的事件. 每監(jiān)聽到對(duì)應(yīng)的系統(tǒng)事件時(shí), 就會(huì)通知 AppDelegate.
Main 函數(shù)作用:
1> 創(chuàng)建 UIApplication 對(duì)象,
2> 創(chuàng)建應(yīng)用程序代理/
3> 開啟時(shí)間循環(huán),. 包括應(yīng)用程序的循環(huán)運(yùn)行, 并開始處理用戶事件.
1.4 什么是 Cocoa 和 Cocoa Touch?
相同之處: 兩者都包含 OC 運(yùn)行時(shí)的兩個(gè)核心框架
cocoa 包含 Foundation 和 AppKit 框架, 可用于開發(fā) Mac OS X 系統(tǒng)的應(yīng)用程序
cocoa touch 包含 Foundation 和 UIKit 框架, 可用于開發(fā)IPhone OS 系統(tǒng)的應(yīng)用程序,
Cocoa 是 Mac OS X 的開發(fā)環(huán)境, Cocoa Touch 是 iPhoen OS 的開發(fā)環(huán)境.
9.0 Swift 相關(guān)
9.1 Swift 內(nèi)聯(lián)函數(shù)是什么? 在什么情況下會(huì)不起作用?
內(nèi)聯(lián)的前提是確定調(diào)用的函數(shù)體內(nèi)容, 將函數(shù)調(diào)用展開成函數(shù)體
以下情況函數(shù)不會(huì)被內(nèi)聯(lián)
1> 函數(shù)體比較長
2> 包含了遞歸調(diào)用.
3> 包含了動(dòng)態(tài)派發(fā).
9.2 舉例說明Swift 里面有哪些類型是 OC 中沒有的?
Swift 引入了在Object-C 中沒有的一些高級(jí)數(shù)據(jù)類型,
例如:
1.tuples 元組. 可以創(chuàng)建和傳遞一組數(shù)值.
2.Optionals 可選項(xiàng)類型 用于處理變量值不存在的情況,
9.3 Swift 中如何阻止方法, 屬性 下標(biāo) 被子類改寫?
在類的定義中使用 final 關(guān)鍵字聲明類, 屬性, 方法和下標(biāo),
final 聲明的類不能被繼承, final 聲明的屬性方法和下標(biāo) 不能被重寫.
如果只是限制一個(gè)方法或者屬性不被重寫, 只需要在該方法和該屬性前加一個(gè) final
如果需要限制整個(gè)類無法被繼承, 那么可以在類名之前加一個(gè) final
9.4 Swift 中 closure 和 OC 中的 Block 有什么區(qū)別?
1.closure 是匿名函數(shù). block 是一個(gè)結(jié)構(gòu)體對(duì)象
2.closure 通過逃逸閉包來在內(nèi)部修改變量, block 通過 __block 修飾符
9.5 什么叫 逃逸閉包? 如何讓一個(gè) 自動(dòng)閉包可以”逃逸”?
逃逸閉包: 一個(gè)傳入函數(shù)的閉包, 如果在函數(shù)執(zhí)行結(jié)束之后才會(huì)被調(diào)用, 那么這個(gè)閉包就稱為逃逸閉包.
如果想讓自動(dòng)閉包可以”逃逸”, 需要同時(shí)使用 @autoclosure 和 @escaping 進(jìn)行修飾.
9.6 Swift 中 Class (類 )和 Struct ( 結(jié)構(gòu)體 ) 的區(qū)別?
1. Class 是引用類型. Struct 是值類型.
2. 類可以被繼承 , 結(jié)構(gòu)體不可以繼承
3. 值類型 struct 被賦予給一個(gè)變量, 常量 或者被傳遞給一個(gè)函數(shù)的時(shí)候, 其值會(huì)被拷貝,
4. 引用類型 class 在被賦予一個(gè)變量 常量 或者傳遞到一個(gè)函數(shù)時(shí) , 其值不會(huì)被拷貝,
- 因此. 引用的是已存在的實(shí)例本身 而不是其拷貝.
9.7 Swift 是面向?qū)ο笳Z言 還是面向過程的函數(shù)式編程語言?
Swift 既是面向?qū)ο蟮? 又是函數(shù)式的編程語言,
因?yàn)镾wift 支持類的封裝, 繼承, 和多態(tài) 所以是面向?qū)ο蟮?
又因 Swift 支持 map. Reduce. filter, flatmap 這類去除中間狀態(tài).數(shù)學(xué)函數(shù)式的方法, 所以也支持面向過程編程.
2.1 Swift 和 OC 的相比有哪些優(yōu)點(diǎn)?
swift 的特點(diǎn)有:
快速, 現(xiàn)代. 安全, 互動(dòng), 而且明顯優(yōu)于 OC
可以使用現(xiàn)有的 Cocoa 和 Cocoa Touch 框架
Swift 取消了 Objective-C 的指針 / 地址 等不安全訪問的使用.
提供命名空間, 泛型, 運(yùn)算對(duì)象重載,
Swift 被簡單的形容為 “ 沒有C 的Objective-C”
為開發(fā)工具 Xcode 帶來了 Xcode Playground 功能, 提供強(qiáng)大的互動(dòng)效果, 能讓 Swift 源代碼在撰寫的過程中實(shí)時(shí)顯示出其運(yùn)行結(jié)果,
基于C 和 OC. 卻沒有C 的一些兼容約束
采用了安全的編程模式
界面基于 Cocoa 和 Cocoa Touch 框架
舍棄 OC 早期應(yīng)用 Smalltalk 的語法, 保留Smalltalk 的動(dòng)態(tài)特性, 全面改為句點(diǎn)表示法.
對(duì)比OC 的動(dòng)態(tài)綁定, 類型嚴(yán)謹(jǐn).
‘