1、Swift對比Objective-C的優(yōu)缺點?
優(yōu)點:
- swift是**類型安全的語言,注重安全,
OC注重靈活 - swift注重面向協(xié)議編程、函數(shù)式編程、面向?qū)ο缶幊?,OC注重面向?qū)ο缶幊?/li>
- swift注重值類型,OC注重指針和引用
- swift是靜態(tài)類型語言,OC是動態(tài)類型語言
- swift中的可選類型,是用于所有數(shù)據(jù)類型,而不僅僅局限于類。相比于OC中的nil更加安全和簡明
- swift中的泛型類型更加方便和通用,而非
OC中只能為集合類型添加泛型 - swift支持函數(shù)式編程,Objc本身是不支持的,需要通過引入ReactiveCocoa這個庫才可支持函數(shù)式編程。
- swift中獨有的元組類型(tuples),把多個值組合成復(fù)合值。元組內(nèi)的值可以是任何類型,并不要求是相同類型的。
- swift新增了兩種權(quán)限,細化權(quán)限。
open>public>internal(默認)>fileprivate>private - swift中各種方便快捷的[高階函數(shù)](函數(shù)式編程)(Swift的標準數(shù)組支持三個高階函數(shù):map,filter和reduce,以及map的擴展flatMap)
缺點:
- 版本不穩(wěn)定
- App體積變大:使用 Swift 后, App 體積大概增加 5-8 M 左右,對體積大小敏感的慎用。(體積變大的原因是因為 Swift 還在變化,所以 Apple 沒有在 iOS 系統(tǒng)里放入 Swift 的運行庫,反而是每個 App 里都要包含其對應(yīng)的 Swift 運行庫。)
- 對于不支持Swift的一些第三方類庫,如果非得使用,只能混合編程,利用橋接文件實現(xiàn)。
- 社區(qū)的開源項目偏少,畢竟OC獨大好多年,很多優(yōu)秀的類庫都不支持Swift,不過這種狀況正在改變,現(xiàn)在有好多優(yōu)秀的Swift的開源類庫了
- 上線方式改變:在上線的時候,不能使用application Loader上傳包文件,會提示你丟失了swift support files,應(yīng)該使用xcode直接上傳。
安全:
- 由于swift的strong static type system,編譯器可幫你檢查出更多問題,而不是在運行時突然boom,還有一個很牛逼的安全特性就是OptionalType。
快速:
- 靜態(tài)語言相對來說語言本身速度更快,swift編譯期間就能生成vtable,確定具體要調(diào)用的方法,比起oc的動態(tài)派發(fā)自然是更快,當然處理到與oc之間的橋接部分,可能不一定比OC快
細節(jié)使用區(qū)別
2、autoReleasePool 創(chuàng)建和釋放?
App啟動后,蘋果在主線程 RunLoop 里注冊了兩個Observer,其回調(diào)都是 _wrapRunLoopWithAutoreleasePoolHandler()。
第一個
Observer監(jiān)視的事件是Entry(即將進入Loop),其回調(diào)內(nèi)會調(diào)用_objc_autoreleasePoolPush()創(chuàng)建自動釋放池。其 order 是 -2147483647,優(yōu)先級最高,保證創(chuàng)建釋放池發(fā)生在其他所有回調(diào)之前。第二個
Observer監(jiān)視了兩個事件:BeforeWaiting(準備進入休眠) 時調(diào)用_objc_autoreleasePoolPop()和_objc_autoreleasePoolPush()釋放舊的池并創(chuàng)建新池;Exit(即將退出Loop) 時調(diào)用_objc_autoreleasePoolPop()來釋放自動釋放池。這個 Observer 的 order 是 2147483647,優(yōu)先級最低,保證其釋放池子發(fā)生在其他所有回調(diào)之后。
在主線程執(zhí)行的代碼,通常是寫在諸如事件回調(diào)、Timer回調(diào)內(nèi)的。這些回調(diào)會被 RunLoop 創(chuàng)建好的 AutoreleasePool 環(huán)繞著,所以不會出現(xiàn)內(nèi)存泄漏,開發(fā)者也不必顯示創(chuàng)建 Pool 了。
3、autoReleasePool 內(nèi)部實現(xiàn)?
4、Socket原理?
5、IOS內(nèi)存管理機制
- MRC & ARC
- TaggedPointer & NONPOINTER_ISA
- 散列表( 引用計數(shù)表 & 弱引用表&自旋鎖)
- 自動釋放池
6、SDWebImage做了哪些工作?
- 1:正在下載該url的圖片,直接返回;
- 2:處理多線程問題,比如cell復(fù)用造成的顯示錯亂問題,也就是下載之前先取消;
- 3:增加一層內(nèi)存緩存,直接從url得到image,NSURLCache存的是data;
- 4:相同url請求時只加了一個finish回調(diào);
- 5:請求做了排隊處理,控制資源。
7、iOS常用設(shè)計模式?
裝飾模式:分類;
代理模式:協(xié)議;
工廠模式:UIButton創(chuàng)建;
原型模式:[object copy];
觀察者模式:KVO;
迭代器模式:數(shù)組的遍歷;
單例模式:Appdelegate;
命令模式:給對象發(fā)消息;
職責(zé)鏈模式:事件傳遞鏈;
中介者模式:模塊解耦;
解釋器模式:Siri語意識別;
8、OC中向一個nil對象發(fā)送消息將會發(fā)生什么?
在 Objective-C 中向 nil 發(fā)送消息是完全有效的——只是在運行時不會有任何作用
- 如果一個方法返回值是一個對象,那么發(fā)送給nil的消息將返回0(nil)
- 如果方法返回值為指針類型,其指針大小為小于或者等于sizeof(void*),float,double,long double 或者 long long 的整型標量,發(fā)送給 nil 的消息將返回0。
- 如果方法返回值為結(jié)構(gòu)體,發(fā)送給 nil 的消息將返回0。結(jié)構(gòu)體中各個字段的值將都是0。
- 如果方法的返回值不是上述提到的幾種情況,那么發(fā)送給 nil 的消息的返回值將是未定義的。
具體原因如下:
objc是動態(tài)語言,每個方法在運行時會被動態(tài)轉(zhuǎn)為消息發(fā)送,即:
objc_msgSend(receiver, selector)。
9、Runloop與事件派發(fā)?
http://www.itdecent.cn/p/c42bffa97934
當一個硬件事件(觸摸/鎖屏/搖晃等)發(fā)生后,首先由 IOKit.framework 生成一個 IOHIDEvent 事件并由 SpringBoard 接收。SpringBoard 只接收按鍵(鎖屏/靜音等),觸摸,加速,接近傳感器等幾種 Event,隨后用 mach port 轉(zhuǎn)發(fā)給需要的App進程。隨后蘋果注冊的那個 Source1 就會觸發(fā)回調(diào),并調(diào)用 _UIApplicationHandleEventQueue() 進行應(yīng)用內(nèi)部的分發(fā)。
10、Dealloc實現(xiàn)原理?
- 首先會調(diào)用 _objc_rootDealloc() 函數(shù)。
-
然后調(diào)用rootDealloc(),在這個函數(shù)內(nèi)部會判斷對象是否可以直接釋放。判斷的條件是判斷當前對象是否使用了非指針型的isa、當前對象是否有weak指針指向他、是否有關(guān)聯(lián)對象、當前對象的內(nèi)部實現(xiàn)是否有c++相關(guān)的內(nèi)容,當前對象是否使用arc管理內(nèi)存、當前對象的引用計數(shù)是否使用散列表來維護的。只有以上條件都不滿足才會調(diào)用object_dispose(),然后結(jié)束,否則調(diào)用c函數(shù) free()處理
截屏2020-11-04 下午3.51.42.png
11、object_dispose()實現(xiàn)?

objc_destructInstance() 實現(xiàn)

12、iOS App 啟動性能優(yōu)化?
https://zhuanlan.zhihu.com/p/28600469
啟動優(yōu)化總結(jié):
- 利用DYLD_PRINT_STATISTICS分析main()函數(shù)之前的耗時
- 重新梳理架構(gòu),減少動態(tài)庫、ObjC類的數(shù)目,減少Category的數(shù)目
- 定期掃描不再使用的動態(tài)庫、類、函數(shù),例如每兩個迭代一次
- 用dispatchonce()代替所有的_attribute((constructor)) 函數(shù)、C++靜態(tài)對象初始化、ObjC的+load
- 在設(shè)計師可接受的范圍內(nèi)壓縮圖片的大小,會有意外收獲
- 利用錨點分析applicationWillFinishLaunching的耗時
- 將不需要馬上在applicationWillFinishLaunching執(zhí)行的代碼延后執(zhí)行
- rootViewController的加載,適當將某一級的childViewController或subviews延后加載
- 如果你的App可能會被后臺拉起并冷啟動,可考慮不加載rootViewController
- 不應(yīng)放過的一些小細節(jié)
- 異步操作并不影響指標,但有可能影響交互體驗,例如大量網(wǎng)絡(luò)請求導(dǎo)致數(shù)據(jù)擁堵
- 有時候一些交互上的優(yōu)化比技術(shù)手段效果更明顯,視覺上的快決不是冰冷的數(shù)據(jù)可以解釋的,好好和你們的設(shè)計師談?wù)剟赢?/li>
12、App啟動過程?
- 解析Info.plist
- 加載相關(guān)信息,例如如閃屏
- 沙箱建立、權(quán)限檢查
- Mach-O加載
- 如果是胖二進制文件,尋找合適當前CPU類別的部分
- 加載所有依賴的Mach-O文件(遞歸調(diào)用Mach-O加載的方法)
- 定位內(nèi)部、外部指針引用,例如字符串、函數(shù)等
- 執(zhí)行聲明為attribute((constructor))的C函數(shù)
- 加載類擴展(Category)中的方法
- C++靜態(tài)對象加載、調(diào)用ObjC的 +load 函數(shù)
- 程序執(zhí)行
- 調(diào)用main()
- 調(diào)用UIApplicationMain()
- 調(diào)用applicationWillFinishLaunching
13、動態(tài)庫靜態(tài)庫區(qū)別?
介紹
- 動態(tài)庫形式:.dylib和.framework
- 靜態(tài)庫形式:.a和.framework
區(qū)別
- 靜態(tài)庫:鏈接時,靜態(tài)庫會被完整地復(fù)制到可執(zhí)行文件中,被多次使用就有多份冗余拷貝(圖1所示)
-
鏈接時不復(fù)制,程序運行時由系統(tǒng)動態(tài)加載到內(nèi)存,供程序調(diào)用,系統(tǒng)只加載一次,多個程序共用,節(jié)省內(nèi)存
圖片
14、為什么刷新UI在主線程?
http://www.itdecent.cn/p/5849eb69ec82
15、__block的實現(xiàn)原理?
https://www.cnblogs.com/feng9exe/p/7486099.html
16、如何理解OC是一門動態(tài)語言?
https://blog.csdn.net/wangsongyang617/article/details/79550045
17、iOS:網(wǎng)絡(luò)優(yōu)化?
https://blog.csdn.net/pk_sir/article/details/107865152
18、為什么要設(shè)計metaclass?
http://www.zyiz.net/tech/detail-111585.html
1、首先會再一次的從類中尋找需要調(diào)用方法的緩存,如果能命中緩存直接返回該方法的實現(xiàn),如果不能命中則繼續(xù)往下走。
2、從類的方法列表中尋找該方法,如果能從列表中找到方法則對方法進行緩存并返回該方法的實現(xiàn),如果找不到該方法則繼續(xù)往下走。
3、從父類的緩存尋找該方法,如果父類緩存能命中則將方法緩存至當前調(diào)用方法的類中(注意這里不是存進父類),如果緩存未命中則遍歷父類的方法列表,之后操作如同第2步,未能命中則繼續(xù)走第3步直到尋找到基類。
4、如果到基類依然沒有找到該方法則觸發(fā)動態(tài)方法解析流程。
5、還是找不到就觸發(fā)消息轉(zhuǎn)發(fā)流程
走到這里一套方法發(fā)送的流程就都走完了,那這跟元類的存在有啥關(guān)系?我們都知道類方法是存儲在元類中的,那么可不可以把元類干掉,在類中把實例方法和類方法存在兩個不同的數(shù)組中?
答:行是肯定可行的,但是在lookUpImpOrForward執(zhí)行的時候就得標注上傳入的cls到底是實例對象還是類對象,這也就意味著在查找方法的緩存時同樣也需要判斷cls到底是個啥。
倘若該類存在同名的類方法和實例方法是該調(diào)用哪個方法呢?這也就意味著還得給傳入的方法帶上是類方法還是實例方法的標識,SEL并沒有帶上當前方法的類型(實例方法還是類方法),參數(shù)又多加一個,而我們現(xiàn)在的objc_msgSend()只接收了(id self, SEL _cmd, ...)這三種參數(shù),第一個self就是消息的接收者,第二個就是方法,后續(xù)的...就是各式各樣的參數(shù)。
通過元類就可以巧妙的解決上述的問題,讓各類各司其職,實例對象就干存儲屬性值的事,類對象存儲實例方法列表,元類對象存儲類方法列表,完美的符合6大設(shè)計原則中的單一職責(zé),而且忽略了對對象類型的判斷和方法類型的判斷可以大大的提升消息發(fā)送的效率,并且在不同種類的方法走的都是同一套流程,在之后的維護上也大大節(jié)約了成本。
19、section和segment 區(qū)別?
section 稱為節(jié),是指在匯編源碼中經(jīng)由關(guān)鍵字section 或segment 修飾、邏輯劃分的指令或數(shù)據(jù)區(qū)域,匯編器會將這兩個關(guān)鍵字修飾的區(qū)域在目標文件中編譯成節(jié),也就是說“節(jié)”最初誕生于目標文件中。
segment 稱為段,是鏈接器根據(jù)目標文件中屬性相同的多個section 合并后的section 集合,這個集合稱為segment,也就是段,鏈接器把目標文件鏈接成可執(zhí)行文件,因此段最終誕生于可執(zhí)行文件中。我們平時所說的可執(zhí)行程序內(nèi)存空間中的代碼段和數(shù)據(jù)段就是指的segment 。
19、Http特性對比
HTTP1.0
- 無狀態(tài)、無連接
HTTP1.1
- 持久連接
- 請求管道化
- 增加緩存處理(新的字段如cache-control)
- 增加Host字段、支持斷點傳輸?shù)?/li>
HTTP2.0
- 二進制分幀 -> 滑動窗口協(xié)議
- 多路復(fù)用(或連接共享)
- 頭部壓縮
- 服務(wù)器推送
20、IOS 死鎖案例
1、
// 非死鎖
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"====");
});
// 死鎖
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"====");
});
2、信號量死鎖一直等待
3、lock鎖死某塊資源不釋放
21、Swift 可選類型底層實現(xiàn)
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
public init(_ some: Wrapped)
}
- Optional是通過enum實現(xiàn)的,Optional本質(zhì)是枚舉。
- 有兩個case,nil和some。
- 關(guān)聯(lián)值就是傳進來的值。
相關(guān)連接
22、iOS調(diào)優(yōu) | 深入理解Link Map File
文件組成
- Object files 最前面的部分是Object files,展示了參與編譯的所有文件序號及路徑(.o文件)
[2] ../test/Debug-iphonesimulator/EaseAPIDemo(TestUtils.o)
[3] ../test/Debug-iphonesimulator/EaseAPIDemo(TestCell.o)
[4] ../test/Debug-iphonesimulator/EaseAPIDemo(TestView.o)
***
[1222] ***Foundation.framework/Foundation
[1223] ***UIKit.framework/UIKit
- Segment & section 接著是section表,是按照 mach-o 文件映射的Segment和section信息。
0x100006AE4 0x0005A5AC __TEXT __text
0x100061090 0x00000984 __TEXT __stubs
0x100061A14 0x0000099C __TEXT __stub_helper
0x1000623B0 0x00001180 __TEXT __const
0x100063530 0x00002B96 __TEXT __objc_methname
0x1000660C6 0x000000D0 __TEXT __objc_classname
0x100066196 0x00000CEC __TEXT __objc_methtype
0x100066E82 0x00013955 __TEXT __cstring
0x10007A7D8 0x000010D2 __TEXT __ustring
0x10007B8AC 0x000000A8 __TEXT __gcc_except_tab
0x10007B954 0x000006A8 __TEXT __unwind_info
0x10007C000 0x000003E0 __DATA __got
0x10007C3E0 0x00000658 __DATA __la_symbol_ptr
0x10007CA38 0x00000AE0 __DATA __const
0x10007D518 0x00000E20 __DATA __cfstring
0x10007E338 0x00000040 __DATA __objc_classlist
0x10007E378 0x00000010 __DATA __objc_nlclslist
0x10007E388 0x00000000 __DATA __objc_catlist
0x10007E388 0x00000020 __DATA __objc_protolist
0x10007E3A8 0x00000008 __DATA __objc_imageinfo
其中__text是代碼段,__data是數(shù)據(jù)段,__cfstring表示C字符常量section,__objc_classlist是全部Objective-C類列表,__objc_classrefs是引用到的Objective-C類列表(不包括通過反射引用的,這點特別注意)。
技巧:使用otool工具獲得各自 __objc_classrefs和 __objc_classlist列表的地址去重后,得到的地址列表就是沒有用到的類地址列表,在通過Link Map找到對應(yīng)地址的無用類即可以刪除無用的類。
otool -v -s __DATA __objc_classlist EaseAPIDemo_v7
- 符號表
接著是符號表,按照Object files表中的文件序號依次列出了所有的方法,地址和占用的空間大小,常量等。示例
0x100001E20 0x000000A0 [ 12] -[EaseAPIDemoInfo init]
0x100001EC0 0x00000240 [ 12] -[EaseAPIDemoInfo parameterInit]
0x100002100 0x00000190 [ 12] -[EaseAPIDemoInfo parameterValidation]
...
//如果是C語言的函數(shù),直接顯示函數(shù)名字,示例:
0x10470E254 0x00000006 [2063] _sqlite3_bind_blob
0x10470E25A 0x00000006 [2063] _sqlite3_bind_double
0x10470E260 0x00000006 [2063] _sqlite3_bind_int
0x10470E266 0x00000006 [2063] _sqlite3_bind_null
0x10470E26C 0x00000006 [2063] _sqlite3_bind_text16
0x10470E272 0x00000006 [2063] _sqlite3_close
根據(jù)以上信息即可分析每一個.o或者framework文件的內(nèi)存占用大小,對于減小包大小有很大幫助。
Link-Map
作用
- 通過分析linkMap文件可以查看每個文件大小,包瘦身可以用到連接
22、WebKit MessageHandle 原理
實現(xiàn)原理:
- 1、JS與iOS約定好jsToOc方法,用作JS在調(diào)用iOS時的方法;
- 2、iOS使用WKUserContentController的-addScriptMessageHandler:name:方法監(jiān)聽name為jsToOc的消息;
- 3、JS通過window.webkit.messageHandlers.jsToOc.postMessage()的方式對jsToOc方法發(fā)送消息;
- 4、iOS在-userContentController:didReceiveScriptMessage:方法中讀取name為jsToOc的消息數(shù)據(jù)message.body。

