iOS開發跳槽入職小米,捋了一下iOS面試知識點

前言

大概捋了一下iOS面試知識點,以此作為大綱希望自己能有目標有計劃地準備面試,后面我會逐個復習一下相應的內容,同時也會添加遺漏的知識點到文本,并記錄下自己的筆記分享出來。喜歡的可以收藏,大家一起努力。

以下是小編收集總結的iOS技術點+面試題分類;看看你都會了嗎?

重點總結-幾大分類:

  • iOS底層原理
  • 性能優化以及架構
  • 多線程、網絡
  • 數據結構算法

iOS底層原理(必問):iOS開發必備能力,也是大廠面試快速篩選人才方式之一。

面試官問:

一、性能優化點
二、項目難點,怎么解決的
三、項目流程迅游有品控審核和reviewcode
四、http怎么發送數據tcp3次握手
五、智能指針,智能指針有什么缺陷
六、釋放不干凈(舉例a=b b=a這種情況)


51、數組和鏈表的區別
- 數組在內存上給出了連續的空間
- 鏈表,內存地址上可以是不連續的,每個鏈表的節點包括原來的內存和下一個節點的信息(單向的一個,雙向鏈表的話,會有兩個)

數組: 
- 優點: 使用方便,查詢效率比鏈表高,內存為一連續的區域 
- 缺點: 大小固定,不適合動態存儲,不方便動態添加

 鏈表: 
- 優點: 可動態添加刪除,大小可變   
- 缺點: 只能通過順次指針訪問,查詢效率低

53、談談你對編譯、鏈接的理解

電子版 iOS面試題+答案:

文章由于答案太多,我做了一個PDF文檔,由于簡書不能上傳文件,,由于文章有限,需要這些文檔的,

點擊騰訊文檔自取吧

展示部分截圖:↓↓↓↓↓

iOS面試文檔
54、leak工具使用
55、應用程序啟動過程,啟動優化
- 應用啟動時是用怎樣加載所有依賴的Mach-O文件的?
- 請列舉你所知道main()函數之前耗時的因素都有哪些

App啟動分為兩種:
- 冷啟動(Cold Launch):從零開始啟動app
- 熱啟動(Warm Launch):app已在內存中,在后臺存活,再次點擊圖標啟動app

啟動時間的優化,主要是針對冷啟動進行優化
1、通過添加環境變量可以打印app的啟動時間分析(詳情請見下圖)
- DYLD_PRINT_STATISTICS
- DYLD_PRINT_STATISTICS_DETAILS(比上一個詳細)
- 一般400毫秒以內正常

打印結果:
Total pre-main time: 238.05 milliseconds (100.0%)              // main函數調用之前(pre-main)總耗時
         dylib loading time: 249.65 milliseconds (104.8%)      // 動態庫耗時 
        rebase/binding time: 126687488.8 seconds (18128259.6%) 
            ObjC setup time:  10.67 milliseconds (4.4%)        // OC結構體準備耗時 
           initializer time:  52.83 milliseconds (22.1%)       // 初始化耗時 
           slowest intializers :                               // 比較慢的加載 
             libSystem.B.dylib :   6.63 milliseconds (2.7%)
   libBacktraceRecording.dylib :   6.61 milliseconds (2.7%)
    libMainThreadChecker.dylib :  31.82 milliseconds (13.3%)

2、冷啟動可以概括為3大階段
- dyld
- runtime
- main

3、dyld(dynamic link editor),Apple的動態連接器,可以裝載Mach-O(可執行文件、動態庫等)
- 裝載app的可執行文件,同時遞歸加載所有依賴的動態庫
- 當dyld把可執行文件、動態庫都裝載完成后,會通知runtime進行下一步處理

4、runtime所做的事情
- 調用map_images函數中調用call_load_methods,調用所有Class和Category的+load方法
- 進行各種objc結構的初始化(注冊objc類、初始化類對象等等)
- 調用C++靜態初始化器和__attribure__((constructor))修飾的函數(JSONKit中存在具體應用)
- 到此為止,可執行文件和動態庫中所有的符號(Class, Protocol, Selector, IMP...)都已按格式成功加載到內存中,被runtime所管理

5、總結
- app的啟動由dylb主導,將可執行文件加載到內存,順便加載所有依賴的動態庫
- 并由runtime負責加載成objc定義的結構
- 所有初始化工作結束后,dyld就會調用main函數
- 接下來就是ApplicationMain函數,AppDelegate的application:didFinishLaunchingWithOptions:方法

6、按照不同的階段優化
dyld
- 減少動態庫、合并一些動態庫(定期清理不必要的動態庫)
- 減少objc類、分類的數量、減少selector數量(定期清理不必要的類、分類)
- 減少C++虛構函數
- Swift盡量使用struct

runtime
- 使用+initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++靜態構造器、Objc的+load方法

main
- 在不影響用戶體驗的前提下,盡可能將一些操作延遲,不要全部都放在finishLaunching方法中
- 按需加載

DYLD_PRINT_STATISTICS設置為1
56、包體積優化
安裝包瘦身(ipa):資源文件、可執行文件

資源文件(圖片、音頻、視頻等)
- 采取無損壓縮(使用工具)
- 去除沒有用到的資源(https://github.com/tinymind/LSUnusedResources)

可執行文件瘦身:
- 編譯器優化(Xcode相關配置)
- 利用AppCode(https://www.jetbrains.com/objc/)檢測未使用的代碼:菜單欄 -> Code -> Inspect Code
- 生成LinkMap,可以查看可執行文件的具體組成
- 可借助第三方工具解析LinkMap文件:http://github.com/huanxsd/LinkMap

57、項目的優化、性能優化
啟動速度:
- 啟動過程中做的事情越少越好(盡可能將多個接口合并)
- 不在UI線程上作耗時的操作(數據的處理在子線程進行,處理完通知主線程刷新節目)
- 在合適的時機開始后臺任務(例如在用戶指引節目就可以開始準備加載的數據)
- 盡量減小包的大小
- 輔助工具(友盟,聽云,Flurry)

頁面瀏覽速度
- json的處理(iOS 自帶的NSJSONSerialization,Jsonkit,SBJson)
- 數據的分頁(后端數據多的話,就要分頁返回,例如網易新聞,或者 微博記錄)
- 數據壓縮(大數據也可以壓縮返回,減少流量,加快反應速度)
- 內容緩存(例如網易新聞的最新新聞列表都是要緩存到本地,從本地加載,可以緩存到內存,或者數據庫,根據情況而定)
- 延時加載tab(比如app有5個tab,可以先加載第一個要顯示的tab,其他的在顯示時候加載,按需加載
- 算法的優化(核心算法的優化,例如有些app 有個 聯系人姓名用漢語拼音的首字母排序)

操作流暢度優化
- Tableview 優化(tableview cell的加載優化)
- ViewController加載優化(不同view之間的跳轉,可以提前準備好數據)

58、說說你自己吧
- 你在項目中技術亮點、難點
- 你的發展方向(職業規劃)
- 你的優點、你的缺點

59、說說組件化,你是如何組件化解耦的
TODO(待填充);??????????

60、靜態庫、動態庫相關
1、什么是庫?
- 共享代碼,實現代碼的復用,一般分為靜態庫和動態庫。

2、靜態庫和動態庫的區別
靜態庫(.a和.framework 樣式):
- 鏈接時完整的拷貝到可執行文件,多次使用多次拷貝,造成冗余,使包變的更大
- 但是代碼裝載速度快,執行速度略比動態庫快

動態庫:(.dylib和.framework)
- 鏈接時不復制,程序運行時由系統加在到內存中,供系統調用,系統加在一次,多次使用,共用節省內存。

3、為什么framework既是靜態又是動態?
- 系統的framework是動態的,自己創建的是靜態的。

4、.a 和 .framework 的區別是什么?
- .a 是單純的二進制文件,需要 .h文件配合,不能直接使用
- .framework是二進制文件+資源文件,可以直接使用。 .framework = .a + .h + sorrceFile(資源文件)


十三、OC對象相關

61、對 OC 中 Class 的源碼理解?其中 cache 的理解?說說NSCache緩存策略
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

62、protocol中能否添加屬性
- OC語言的協議里面是支持聲明屬性的
- 但在協議中聲明屬性其實和在其中定義方法一樣,只是聲明了getter和setter方法,并沒有具體實現

63、OC內聯函數 inline
作用:
- 替代宏

inline函數與宏有區別
- 解決函數調用效率的問題
- 函數之間調用,是內存地址之間的調用,當函數調用完畢之后還會返回原來函數執行的地址。
- 函數調用有時間開銷,內聯函數就是為了解決這一問題

inline相比于宏的優點
- 避免了宏的缺點:需要預編譯.因為inline內聯函數也是函數,不需要預編譯.
- 編譯器在調用一個內聯函數時,會首先檢查它的參數的類型,保證調用正確。消除了它的隱患和局限性。
- 可以使用所在類的保護成員及私有成員

inline相比于函數的優點
- inline函數避免了普通函數的,在匯編時必須調用call的缺點:取消了函數的參數壓棧,減少了調用的開銷,提高效率.所以執行速度確比一般函數的執行速度要快.
- 集成了宏的優點,使用時直接用代碼替換(像宏一樣)

64、id和NSObject ,instancetype的區別?
- id和instancetype都可以做方法的返回值。

- id類型的返回值在編譯期不能判斷對象的真實類型,即非關聯返回類型
- instancetype類型的返回值在編譯期可以判斷對象的真實類型,即關聯返回類型。

- id可以用來定義變量, 可以作為返回值, 可以作為形參
- instancetype只能用于作為返回值。

非關聯返回類型、關聯返回類型
TODO(待填充);??????????

65、方法簽名有什么作用?
TODO(待填充);??????????

66、nil、Nil、NULL、NSNull的區別?
- nil:指向一個對象的空指針    
- Nil:指向一個類的空指針,   
- NULL:指向其他類型(如:基本類型、C類型)的空指針, 用于對非對象指針賦空值.
- NSNull:在集合對象中,表示空值的對象.

NSNull在Objective-C中是一個類 .NSNull有 + (NSNull *)null; 單例方法.多用于集合(NSArray,NSDictionary)中值為空的對象.

NSArray *array = [NSArray arrayWithObjects: [[NSObject alloc] init], [NSNull null], @"aaa", nil, [[NSObject alloc] init], [[NSObject alloc] init], nil];
NSLog(@"%ld", array.count);// 輸出 3,NSArray以nil結尾

67、NSDictionary底層實現原理
- 在OC中NSDictionary是使用hash表來實現key和value的映射和存儲的。

hash表存儲過程簡單介紹:
- 根據key值計算出它的hash值h;
- 假設箱子的個數是n,那么鍵值對應該放在第(h%n)個箱子中。
- 如果該箱子中已經有了鍵值對,就是用開放尋址法或者拉鏈法解決沖突。使用拉鏈法解決哈希沖突時,每個箱子其實是一個鏈表,屬于同一個箱子的所有鍵值對都會排列在鏈表中。

68、父類的property是如何查找的?
- 子類中的propert_list、method_list、ivar_list并不包含父類
- 子類對象的_IMPL包含父類的

從以上幾點回答
TODO(待填充);??????????

69、+load與 +initialize
共同點:
- 方法只會執行一次
- 在類使用之前,就自動調用了這兩個方法

區別:
- 執行時機不同()

- load方法:如果類自身沒有定義,并不會調用其父類的load方法;
- initialize方法:如果類自身沒有定義,就會調用其父類的initialize方法;

執行的前提條件:
- load 只要類所在文件被引用,就會執行; 
- 如果類沒有引用進項目,就不會有load的執行; 
- initialize 需要類或者其子類的第一個方法被調用,才會執行,而且是在第一個方法執行之前,先執行; 
- 即使類文件被引用進項目,但是沒有使用,那么initialize就不會調用執行;

70、iOS如何實現多繼承,代碼書寫一下
- 使用協議組合
- NSProxy

TODO(待填充);??????????

71、類與結構體的區別
- 結構體只能封裝數據,而類還可以封裝行為
- 賦值:結構體是拷貝,對象之間是地址
- 結構體變量分配在棧空間(如果是一個局部變量的情況下),而對象分配在堆空間

72、crash崩潰怎么解,崩潰到底層代碼
NSSetUncaughtExceptionHandler可以統計閃退
TODO(待填充);??????????

73、屬性、成員變量、set、get方法相關
- 屬性可以與set方法和get方法 三者同時存在嗎,如果不行,請說明原因?
換句話說就是:iOS中同時重寫屬性的set與get方法時,為什么訪問不了下劃線屬性?

原因:
- 屬性的setter方法和getter方法是不能同時進行重寫,
- 因為,一旦你同時重寫了這兩個方法,那么系統就不會幫你生成這個成員變量了

解決方式:
@synthesize authType = _authType;
- 意思是,將屬性的setter,getter方法,作用于這個變量。

74、isa和superclass相關
1、對象的isa指針指向哪里?superclass指針呢?(??圖-總結圖)
- instance的isa指向class
- class的isa指向meta-class
- meta-class的isa指向基類的meta-class

- class的superclass指向父類的class(如果沒有父類,superclass指針為nil)
- meta-class的superclass指向父類的meta-class
- ??基類的meta-class的superclass指向基類的class

2、方法調用查找(??????圖-instance調用對象的軌跡;圖-類方法調用軌跡)
- 對象方法的調用:通過instance的isa找到class,最后找到對象方法的實現進行調用
- 類方法的調用:當調用類方法時,通過class的isa找到meta-class,最后找到類方法的實現進行調用

3、class對象的superclass指針
Student : Person : NSObject

當Student的instance對象要調用Personal的對象方法時:
- 先通過isa找到Student的class,然后通過superclass找到Person的class,最后找到對象方法的實現進行調用

4、meta-class對象的superclass指針
當Student的class要調用Person的類方法時
- 先通過isa找到Student的meta-class,然后通過superclass找到Person的meta-class,最后找到類方法的實現進行調用

image
image
image
image
image
image
75、OC的類信息存放在哪里?
- 對象方法、屬性、成員變量、協議信息,存放在class對象中
- 類方法,存放在meta-class對象中
- 成員變量的具體值,存放在instance對象中

76、class、meta-class的結構

struct objc_class : objc_object {
    Class ISA;
    Class superclass;
    cache_t cache;             // 方法緩存
    class_data_bits_t bits;    // 用于獲取具體的類信息
}

& FAST_DATA_MASK

struct class_rw_t {
    uint32_t flags;
    uint32_t version;
    const class_ro_t *ro;        // 
    method_array_t methods;      // 方法列表
    property_array_t properties; // 屬性列表
    protocol_array_t protocols;  // 協議列表
    Class firstSubclass;
    Class nextSiblingClass;
    char *demangledName;
}

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name; // 類名
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars; // 成員變量列表

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;
}

推薦閱讀:iOS熱門面試技術文集

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容