iOS面試-經(jīng)典100題

iOS經(jīng)典面試題匯總:初級(jí)、中級(jí)、高級(jí)工程師分類版

一、初級(jí)工程師核心面試題(基礎(chǔ)與實(shí)操)

初級(jí)職位重點(diǎn)考察語言基礎(chǔ)、UIKit基礎(chǔ)、界面開發(fā)以及基本的應(yīng)用生命周期管理。

1. Swift基礎(chǔ)與語法

Q1:Swift 中letvar 的區(qū)別是什么?
參考答案:
let 用于聲明常量,值一旦設(shè)定不可更改;
var 用于聲明變量,值可以隨后修改。

注意:
面試中若被追問 :let 聲明的數(shù)組是否絕對(duì)不可變?
答案:數(shù)組本身不可替換,但若元素是類對(duì)象,其屬性仍可變。

Q2:Swift 中的“可選型(Optional)”是什么?如何安全地解包?
參考答案:
Optional 是 Swift 的一種類型,表示要么有值,要么是 nil。安全解包的方式包括:

  • 可選綁定(Optional Binding): if let / guard let
  • 空合運(yùn)算符(Nil Coalescing): ?? 提供默認(rèn)值
  • 可選鏈(Optional Chaining): ?.

注意:guard let 因其能提前退出函數(shù)、減少嵌套,通常被視為最佳實(shí)踐。

Q3:Swift 中StructClass 的核心區(qū)別是什么?
參考答案:

  • 類型: Struct 是值類型(拷貝),Class 是引用類型(共享)。
  • 內(nèi)存: Struct 分配在棧上(高效),Class 分配在堆上(需要ARC管理)。
  • 繼承: Class 支持繼承,Struct 不支持。
  • 線程安全: Struct 在默認(rèn)線程安全上通常優(yōu)于 Class。

注意:
面試中若被追問 “Swift 為何推薦優(yōu)先用 Struct?”
答案:值類型天然線程安全、內(nèi)存開銷小、無循環(huán)引用風(fēng)險(xiǎn),符合 Swift 的 “安全優(yōu)先” 設(shè)計(jì)理念。

2. UI與布局

Q4:UIView 的 framebounds 有何不同?
參考答案:

  • frame: 相對(duì)于父視圖坐標(biāo)系的位置和大小。
  • bounds: 相對(duì)于自身坐標(biāo)系的位置和大?。ㄍǔ?origin 為(0,0)),
    • size大小改變會(huì)影響 frame
    • origin 改變會(huì)影響子視圖的顯示位置。

Q5:解釋 iOS 中的應(yīng)用生命周期(App Lifecycle)。
參考答案:

  • Not Running: 未啟動(dòng)
  • Inactive: 前臺(tái)但不接收事件(如電話打斷)
  • Active: 前臺(tái)且接收事件
  • Background: 后臺(tái)執(zhí)行代碼
  • Suspended: 后臺(tái)掛起,不執(zhí)行代碼
  • Terminated: 終止 應(yīng)用被系統(tǒng) / 用戶強(qiáng)制關(guān)閉

面試加分點(diǎn):
Background → Suspended:應(yīng)用進(jìn)入后臺(tái)后,若沒有申請(qǐng)后臺(tái)任務(wù)權(quán)限(如音頻、定位),系統(tǒng)會(huì)在幾秒內(nèi)將其掛起;
Suspended 狀態(tài)下:應(yīng)用不占用 CPU 資源,內(nèi)存仍保留(但系統(tǒng)可能因內(nèi)存不足直接殺死,進(jìn)入 Not Running)。

??键c(diǎn):
AppDelegateSceneDelegate 中的對(duì)應(yīng)回調(diào)方法,如 applicationDidEnterBackground

··注意:
管理場(chǎng)景級(jí)生命周期:iOS 13 前使用AppDelegate ,iOS 13 后 使用SceneDelegate

Q6:什么是自動(dòng)布局(Auto Layout)?為什么需要它?
參考答案:
Auto Layout(自動(dòng)布局) 是蘋果從iOS 6開始引入的、基于約束(Constraint)的布局系統(tǒng)。
它根據(jù)視圖之間的相對(duì)關(guān)系動(dòng)態(tài)計(jì)算尺寸和位置,用以適配不同屏幕尺寸和動(dòng)態(tài)類型(Dynamic Type)變化。

簡潔答案:
Auto Layout 是基于約束(Constraint)的布局系統(tǒng),通過相對(duì)關(guān)系自動(dòng)計(jì)算視圖位置和大小,主要用來適配多屏幕、動(dòng)態(tài)內(nèi)容、橫豎屏切換和動(dòng)態(tài)字體,是 iOS 開發(fā)里界面適配的核心方案。

3. 內(nèi)存管理基礎(chǔ)

Q7:什么是 ARC?它是如何工作的?
參考答案:
ARC 即 Automatic Reference Counting,自動(dòng)引用計(jì)數(shù),是 iOS 中用于管理 Objective?C / Swift 對(duì)象生命周期的內(nèi)存管理機(jī)制,由 LLVM 編譯器與 Objective?C Runtime 共同協(xié)作實(shí)現(xiàn)。

ARC的工作原理:

  1. 每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù),表示當(dāng)前有多少個(gè)強(qiáng)引用指向它。
  2. 對(duì)象被強(qiáng)引用時(shí),引用計(jì)數(shù) +1;強(qiáng)引用斷開時(shí),引用計(jì)數(shù) -1。
  3. 當(dāng)引用計(jì)數(shù)變?yōu)?0 時(shí),對(duì)象會(huì)被立即釋放,內(nèi)存回收。
  4. LLVM 編譯器在編譯階段自動(dòng)插入 retain/release/autorelease 相關(guān)代碼。
  5. Runtime 負(fù)責(zé)維護(hù)引用計(jì)數(shù)、處理 weak 引用,并在對(duì)象銷毀時(shí)將所有指向它的 weak 指針自動(dòng)置為 nil。

加分項(xiàng)

  1. ARC 不是垃圾回收 GC
    GC 是運(yùn)行時(shí)掃描,ARC 是編譯期插碼 + 運(yùn)行時(shí)配合,性能更高、更穩(wěn)定。
  2. ARC 只管理 OC/Swift 對(duì)象
    不管理 C 語言的 malloc/free、CoreFoundation 對(duì)象,需要手動(dòng)管理或橋接。
  3. 引用類型決定內(nèi)存行為
    • strong:強(qiáng)引用,持有對(duì)象,引用計(jì)數(shù) +1
    • weak:弱引用,不持有,對(duì)象銷毀自動(dòng)置 nil,防止野指針
    • unowned:無主引用,不持有,對(duì)象銷毀不置 nil
  4. ARC 不能解決循環(huán)引用
    兩個(gè)對(duì)象互相強(qiáng)持有會(huì)導(dǎo)致引用計(jì)數(shù)永遠(yuǎn)不為 0,必須用 weak/unowned 打破。

Q8:strong, weakunowned 關(guān)鍵字在 ARC 中的作用?
參考答案:

  • strong: 是強(qiáng)引用,增加引用計(jì)數(shù),只要有強(qiáng)引用對(duì)象就不會(huì)銷毀;
  • weak: 是弱引用,不增加引用計(jì)數(shù),對(duì)象銷毀后自動(dòng)置 nil,必須是 var Optional,用來解決 Delegate 這類循環(huán)引用;
  • unowned: 無主引用,不增加引用計(jì)數(shù),假定被引用對(duì)象生命周期更長,訪問銷毀對(duì)象會(huì)崩潰,比如車主和車的強(qiáng)關(guān)聯(lián)場(chǎng)景。

加分項(xiàng)

  1. weak vs unowned 核心差異:
  • 安全性:weak 是 “安全弱引用”(自動(dòng)置 nil),unowned 是 “不安全弱引用”(訪問銷毀對(duì)象崩潰);
  • 語法要求:weak 必須是var Optional,unowned 可聲明為let/var 非Optional;
  • 場(chǎng)景細(xì)分:weak 用于 “被引用對(duì)象可能先銷毀”(如 Delegate),unowned 用于 “1:1 強(qiáng)關(guān)聯(lián)且被引用對(duì)象生命周期更長”(如車主 - 車、閉包中明確不銷毀的 self)。
  1. 循環(huán)引用解決方案:
  • 類間循環(huán)引用(如 A 強(qiáng)引用 B,B 強(qiáng)引用 A):用 weak 修飾其中一方;
  • 閉包循環(huán)引用(self 強(qiáng)引用閉包,閉包捕獲 self):用[weak self](可選 self)或[unowned self](確定 self 不銷毀);
  • 特殊場(chǎng)景(如 Core Data 的 NSManagedObject):優(yōu)先用 unowned(框架保證生命周期)。
    3 .OC 與 Swift 的細(xì)微區(qū)別:
  • OC 中 weak 修飾的變量必須是對(duì)象類型,Swift 中 weak 僅適用于類類型(需遵循 AnyObject);
  • OC 中 unowned 對(duì)應(yīng)__unsafe_unretained(行為一致,訪問銷毀對(duì)象崩潰),Swift 的 unowned 更嚴(yán)格(編譯期校驗(yàn)非 Optional)。

4. 編程基礎(chǔ)概念

Q9:什么是代理模式(Delegate)?在 iOS 中如何實(shí)現(xiàn)?
參考答案:
代理是一種對(duì)象間的通信模式.
核心邏輯是:一個(gè)對(duì)象(委托方)將部分職責(zé)委托給另一個(gè)對(duì)象(代理方),代理方遵循雙方約定的協(xié)議完成特定操作,或接收委托方的事件通知,本質(zhì)是實(shí)現(xiàn)對(duì)象間的解耦,讓委托方無需依賴代理方的具體類型,僅依賴協(xié)議通信。

加分項(xiàng)

  1. 設(shè)計(jì)層面
    解耦價(jià)值:代理模式遵循 “依賴倒置原則”,委托方僅依賴協(xié)議(抽象)而非代理方(具體),比如 UITableView 無需知道控制器的類型,只需通過 UITableViewDelegate 就能完成事件傳遞,降低代碼耦合度;
    場(chǎng)景適配:對(duì)比 Block / 通知,代理更適合 “一對(duì)一、需要返回值、強(qiáng)關(guān)聯(lián)” 的場(chǎng)景(如 tableView:heightForRowAtIndexPath: 需要返回行高),而 Block 更適合一次性回調(diào),通知適合一對(duì)多通信。
  2. 技術(shù)細(xì)節(jié)
    內(nèi)存安全:delegate 必須用 weak 修飾,因?yàn)槲蟹剑ㄈ?CustomView)會(huì)持有 delegate,若代理方(如 ViewController)再持有委托方,會(huì)形成循環(huán)引用導(dǎo)致內(nèi)存泄漏;若代理方是基本數(shù)據(jù)類型(極少場(chǎng)景),可用 assign,但 iOS 中幾乎都是對(duì)象類型,優(yōu)先用 weak;
    調(diào)用安全:調(diào)用代理方法前必須通過 respondsToSelector: 判斷方法是否實(shí)現(xiàn),尤其是 @optional 方法,避免因代理未實(shí)現(xiàn)方法導(dǎo)致崩潰(面試高頻考點(diǎn));
    命名規(guī)范:協(xié)議名 = 委托方類名 + Delegate(如 UITableViewDelegate),代理方法名需體現(xiàn) “委托方 + 操作”(如 tableView:didSelectRowAtIndexPath:),符合蘋果官方編碼規(guī)范。
  3. 進(jìn)階拓展
    代理鏈:可實(shí)現(xiàn)多層代理(如 View → ViewController → Model 層),但需注意層級(jí)不宜過深,否則增加調(diào)試成本;
    反向代理:若代理方需要主動(dòng)向委托方傳遞數(shù)據(jù),可給代理方也聲明 delegate,形成雙向代理(如播放器控件與控制器的雙向通信);
    Swift 中的差異:Swift 中代理協(xié)議需標(biāo)記 @objc 才能用 weak(因?yàn)?weak 僅支持類對(duì)象),或讓協(xié)議繼承 AnyObject;可選方法用 optional 修飾,且需協(xié)議帶 @objc。

Q10:解釋一下 #import#include, @class 的區(qū)別。
參考答案:
#import 是 Objective-C 中導(dǎo)入頭文件的方式,能確保文件只被包含一次;
#include 是 C 的導(dǎo)入方式,需配合宏防止重復(fù)包含。
@class 是前向聲明,用于告訴編譯器存在某個(gè)類,減少編譯依賴和解決循環(huán)引用。

加分項(xiàng)

  1. 編譯效率層面:@class 僅做聲明不解析文件內(nèi)容,相比#import能減少預(yù)編譯階段的文件解析量,尤其在百萬行級(jí)別的大型工程中,統(tǒng)一使用 “頭文件 @class 聲明 + 實(shí)現(xiàn)文件 #import 導(dǎo)入” 的規(guī)范,可顯著降低整體編譯耗時(shí);
  2. 循環(huán)引用細(xì)節(jié):除了類之間的循環(huán)導(dǎo)入,@protocol(協(xié)議)的循環(huán)引用也可通過@protocol ProtocolName;(協(xié)議前向聲明)解決,原理與@class一致;
    底層機(jī)制補(bǔ)充:Xcode 中#import <Foundation/Foundation.h> 能直接使用,本質(zhì)是系統(tǒng)已將 Foundation 的頭文件路徑加入編譯器的搜索路徑,而自定義頭文件用#import "XXX.h" 是從當(dāng)前文件目錄開始搜索,這也是#import的路徑搜索特性(C 的#include同理);
  3. Swift 對(duì)比(可選):Swift 中無#import/#include/@class,而是通過import導(dǎo)入模塊(如import UIKit),模塊機(jī)制從底層杜絕了重復(fù)導(dǎo)入問題,是對(duì) OC 頭文件機(jī)制的徹底優(yōu)化。

二、中級(jí)工程師進(jìn)階面試題(原理與架構(gòu))

中級(jí)職位側(cè)重于多線程、內(nèi)存管理細(xì)節(jié)、運(yùn)行時(shí)以及框架原理。

5. 并發(fā)編程

Q11:GCD 與 NSOperationQueue 的區(qū)別及各自的適用場(chǎng)景?
參考答案:

  • GCD: 輕量級(jí),基于 C 的 API,用于執(zhí)行一次性的、簡單的任務(wù)(如 dispatch_async)。
  • NSOperationQueue: 是對(duì) GCD 的 Objective-C 封裝,支持任務(wù)取消、任務(wù)依賴、狀態(tài)監(jiān)控(KVO),適合管理復(fù)雜的、相互依賴的異步任務(wù)。

加分項(xiàng)

  1. 性能細(xì)節(jié):GCD 雖輕量,但 NSOperationQueue 的性能損耗在絕大多數(shù)業(yè)務(wù)場(chǎng)景下可忽略,且面向?qū)ο蟮姆庋b大幅提升代碼可維護(hù)性;
  2. 擴(kuò)展能力:NSOperation 可自定義子類(如重寫 main/start 方法),支持任務(wù)執(zhí)行狀態(tài)的自定義邏輯(如超時(shí)處理),而 GCD 需手動(dòng)封裝;
  3. 取消機(jī)制:GCD 的 block 提交后無法原生取消,需通過 volatile 標(biāo)記位手動(dòng)控制,而 NSOperation 的 cancel 方法可直接終止未執(zhí)行的任務(wù),已執(zhí)行的任務(wù)需在內(nèi)部判斷 isCancelled;
  4. QoS 適配:兩者均支持 iOS 8+ 的 Quality of Service(服務(wù)質(zhì)量),但 NSOperation 可通過 qualityOfService 為單個(gè)任務(wù)設(shè)置 QoS,更靈活;
  5. 實(shí)際開發(fā)建議:簡單場(chǎng)景優(yōu)先用 GCD(快速、輕量),復(fù)雜任務(wù)管理優(yōu)先用 NSOperationQueue(易維護(hù)、功能全),避免過度封裝或過度簡化。

Q12:什么是死鎖?請(qǐng)舉例說明在主線程調(diào)用 sync 函數(shù)為什么可能導(dǎo)致死鎖?
參考答案:
死鎖是多線程 / 多任務(wù)場(chǎng)景下的一種資源競(jìng)爭狀態(tài):兩個(gè)或多個(gè)任務(wù)(線程 / 隊(duì)列任務(wù))各自持有對(duì)方所需的資源,同時(shí)又等待對(duì)方釋放資源,最終導(dǎo)致所有任務(wù)陷入 “互相等待、永久阻塞” 的狀態(tài),無法繼續(xù)執(zhí)行,程序卡死。

如果在主線程(串行隊(duì)列)調(diào)用 DispatchQueue.main.sync { ... },由于 sync 會(huì)阻塞當(dāng)前線程并等待任務(wù)完成,而當(dāng)前線程正是主線程,被提交的 Block 也在等待主線程空閑才能執(zhí)行,形成互相等待,導(dǎo)致死鎖。

加分項(xiàng)

  1. 死鎖的四大必要條件(體現(xiàn)底層理解)
    死鎖的形成必須同時(shí)滿足 4 個(gè)條件,缺一不可:
  • 互斥:資源(如線程執(zhí)行權(quán))只能被一個(gè)任務(wù)獨(dú)占;
  • 占有且等待:任務(wù)持有部分資源,同時(shí)等待其他任務(wù)的資源;
  • 不可搶占:已分配的資源無法被強(qiáng)制剝奪,只能主動(dòng)釋放;
  • 循環(huán)等待:任務(wù)間形成環(huán)形等待鏈(如主線程←→Block)。
  1. 擴(kuò)展場(chǎng)景(體現(xiàn)知識(shí)遷移能力)
    并非只有主線程會(huì)觸發(fā)此類死鎖,任意串行隊(duì)列在自身隊(duì)列內(nèi)同步派發(fā)任務(wù)都會(huì)死鎖:
// 自定義串行隊(duì)列死鎖示例
let serialQueue = DispatchQueue(label: "serial.queue")
serialQueue.async {
    // 串行隊(duì)列內(nèi)同步派發(fā)任務(wù)到自身,觸發(fā)死鎖
    serialQueue.sync {
        print("永遠(yuǎn)不會(huì)執(zhí)行")
    }
}
  1. 解決方案(體現(xiàn)工程實(shí)踐能力)
    避免自同步:不在串行隊(duì)列中對(duì)自身執(zhí)行sync操作;
    優(yōu)先用 async:非必須等待結(jié)果時(shí),使用async(異步派發(fā))替代sync;
    線程判斷優(yōu)化:確需同步執(zhí)行時(shí),先判斷當(dāng)前線程,避免重復(fù)阻塞:
func executeOnMain(_ task: @escaping ()->()) {
    if Thread.isMainThread {
        task() // 主線程直接執(zhí)行,不派發(fā)
    } else {
        DispatchQueue.main.sync(execute: task) // 非主線程同步執(zhí)行
    }
}
  1. 排查技巧:通過 Xcode 的 “Debug Navigator” 查看線程調(diào)用棧,定位sync死鎖點(diǎn);使用 Instruments 的 Thread Sanitizer 檢測(cè)死鎖風(fēng)險(xiǎn)。

Q13:DispatchGroup 的作用是什么?
參考答案:
DispatchGroup 是 GCD 提供的任務(wù)分組管理工具,核心作用是追蹤一組異步 / 同步任務(wù)的執(zhí)行狀態(tài)

  1. 可監(jiān)聽組內(nèi)所有任務(wù)的完成狀態(tài),當(dāng)全部任務(wù)執(zhí)行完畢后,通過 notify方法觸發(fā)統(tǒng)一回調(diào)(非阻塞);
  2. 也可通過 wait 方法主動(dòng)阻塞當(dāng)前線程,等待組內(nèi)任務(wù)全部完成(可設(shè)置超時(shí)時(shí)間);
  3. 典型應(yīng)用場(chǎng)景是多網(wǎng)絡(luò)請(qǐng)求、多文件下載等異步任務(wù)完成后,統(tǒng)一刷新 UI 或執(zhí)行后續(xù)邏輯。

6. 架構(gòu)與設(shè)計(jì)模式

Q14:MVC 在 iOS 中的問題是什么?MVVM 如何改進(jìn)它?
參考答案:

  • MVC 問題: Controller 負(fù)責(zé) Model 與 View 的綁定和邏輯處理,導(dǎo)致 Controller 異常臃腫(Massive View Controller)。
  • MVVM 改進(jìn): 引入 ViewModel,將 Controller 中的業(yè)務(wù)邏輯和視圖狀態(tài)(如數(shù)據(jù)格式化、按鈕是否可用)轉(zhuǎn)移到 ViewModel 中,通過數(shù)據(jù)綁定(如 Combine 或 KVO)連接 View,使 Controller 變得更輕量,且 ViewModel 更易于測(cè)試。

Q15:iOS 開發(fā)中常見的設(shè)計(jì)模式有哪些?舉例說明。
參考答案:

  • 單例(Singleton): 確保一個(gè)類只有一個(gè)實(shí)例(如 UserDefaults.standard)。
  • 工廠(Factory): 根據(jù)輸入創(chuàng)建不同對(duì)象。
  • 觀察者(Observer): 如通知中心(NotificationCenter)和 KVO。
  • 責(zé)任鏈(Chain of Responsibility): 如 UIResponder 的事件傳遞機(jī)制。

7. 運(yùn)行時(shí)與語言特性

Q16:什么是 Category(分類)?它有哪些優(yōu)點(diǎn)和局限性?
參考答案:
Category 用于為現(xiàn)有類添加方法(包括系統(tǒng)類)。

  • 優(yōu)點(diǎn): 功能模塊化、代碼局部化、模擬多繼承。
  • 局限性: 無法直接添加成員變量(需通過關(guān)聯(lián)對(duì)象添加),如果分類與主類方法重名,會(huì)“覆蓋”主類方法(實(shí)際是分類方法在方法列表中靠前)。

Q17:解釋 KVC(Key-Value Coding,鍵值編碼) 與 KVO(Key-Value Observing,鍵值觀察)。
參考答案:

  • KVC: 通過字符串鍵(Key)間接訪問對(duì)象屬性(setValue:forKey:)。底層會(huì)拆解 Key,調(diào)用相應(yīng)的 getter/setter 或訪問成員變量。
  • KVO: 基于 KVC 和運(yùn)行時(shí)機(jī)制,當(dāng)被觀察對(duì)象的屬性發(fā)生變化時(shí),自動(dòng)通知觀察者。底層會(huì)動(dòng)態(tài)生成子類并重寫 setter 方法。

Q18:Block 是如何在內(nèi)存中工作的?__block 關(guān)鍵字的作用?
參考答案:

  • Block 有三種類型:_NSConcreteGlobalBlock(全局,無捕獲)、_NSConcreteStackBlock(棧上,需拷貝)、_NSConcreteMallocBlock(堆上)。
  • __block 用于允許在 Block 內(nèi)部修改捕獲的外部變量,它會(huì)將變量包裝成一個(gè)結(jié)構(gòu)體,并拷貝到堆上。

8. 框架原理

Q19:簡述 UITableView 的復(fù)用機(jī)制。
參考答案:
當(dāng) Cell 滑出屏幕時(shí),會(huì)被放入復(fù)用池(Reuse Pool)。當(dāng)新的 Cell 即將出現(xiàn)時(shí),會(huì)通過 dequeueReusableCell(withIdentifier:) 從池中取出一個(gè)閑置 Cell 進(jìn)行重新配置(重置數(shù)據(jù)),以此減少內(nèi)存分配和對(duì)象創(chuàng)建的開銷。

Q20:什么是離屏渲染(Offscreen Rendering)?它為什么會(huì)影響性能?
參考答案:
離屏渲染指 GPU 在當(dāng)前屏幕緩沖區(qū)外新開辟緩沖區(qū)進(jìn)行渲染,需要多次上下文切換。觸發(fā)場(chǎng)景包括:設(shè)置圓角(cornerRadiusmasksToBounds 結(jié)合)、設(shè)置陰影(shadowPath 未指定)、圖層蒙版(mask)。優(yōu)化方法:使用帶圓角的資源圖片,或指定 shadowPath。

Q21:+load+initialize 方法的區(qū)別?
參考答案:

  • +load 當(dāng)類被加載進(jìn)內(nèi)存時(shí)調(diào)用(應(yīng)用啟動(dòng)時(shí)),僅調(diào)用一次。如果分類也實(shí)現(xiàn)了,會(huì)覆蓋主類。
  • +initialize 在類第一次接收到消息(如首次調(diào)用方法)前調(diào)用,可能存在多次(子類未實(shí)現(xiàn)會(huì)調(diào)用父類的)。

三、高級(jí)工程師深度面試題(系統(tǒng)與優(yōu)化)

高級(jí)職位關(guān)注性能優(yōu)化、崩潰分析、底層原理、跨端以及架構(gòu)設(shè)計(jì)。

9. 性能優(yōu)化與監(jiān)控

Q22:如何檢測(cè)和解決 iOS 應(yīng)用的啟動(dòng)優(yōu)化問題?
參考答案:
啟動(dòng)分為 pre-mainmain 之后兩個(gè)階段。

  • pre-main: 動(dòng)態(tài)庫加載、Rebase/Bind、Objective-C 類注冊(cè)。優(yōu)化:減少動(dòng)態(tài)庫、合并靜態(tài)庫、減少 Objective-C 分類(+load 方法過多)。
  • main 之后: didFinishLaunching 中的任務(wù)優(yōu)化。優(yōu)化:懶加載、任務(wù)優(yōu)先級(jí)劃分(將非必要任務(wù)延遲啟動(dòng))、使用 dispatch_async 異步執(zhí)行。

Q23:Instruments 工具中,如何使用 Time Profiler 和 Leaks 來排查性能問題?
參考答案:

  • Time Profiler: 采樣分析 CPU 占用,找出耗時(shí)函數(shù)(通常在主線程中執(zhí)行大量計(jì)算或 I/O 會(huì)導(dǎo)致卡頓)。
  • Leaks: 檢測(cè)內(nèi)存泄漏,結(jié)合 Allocations 查看對(duì)象是否未釋放。如果發(fā)現(xiàn)泄漏,可以通過 Xcode 的 Debug Memory Graph 快速定位循環(huán)引用點(diǎn)。

Q24:什么是 Method Swizzling?它有哪些風(fēng)險(xiǎn)?
參考答案:
Method Swizzling 是運(yùn)行時(shí)交換兩個(gè)方法實(shí)現(xiàn)的技術(shù),通常用于 AOP(面向切面編程,如埋點(diǎn))。風(fēng)險(xiǎn):

  • 線程安全性: 應(yīng)在 +load 中執(zhí)行,保證線程安全。
  • 命名沖突: 可能導(dǎo)致系統(tǒng)方法被覆蓋。
  • 方法順序: 交換后的調(diào)用順序可能導(dǎo)致不可預(yù)知結(jié)果。

10. 底層原理與架構(gòu)

Q25:簡述 RunLoop 的內(nèi)部機(jī)制。它是如何實(shí)現(xiàn)“有事件就處理,沒事件就休眠”的?
參考答案:
RunLoop 是一個(gè)事件循環(huán),本質(zhì)是 do-while 循環(huán)。

  • 機(jī)制: 監(jiān)聽 Source0(輸入源)、Source1(基于端口的系統(tǒng)事件)、Timer、Observer。
  • 休眠原理: 當(dāng)沒有事件時(shí),線程進(jìn)入 mach_msg 陷阱(trap),由內(nèi)核態(tài)管理,等待內(nèi)核喚醒(如觸摸事件、定時(shí)器觸發(fā))。這避免了 CPU 空轉(zhuǎn),節(jié)約資源。

Q26:App 閃退(Crash)的主要類型有哪些?如何捕獲并進(jìn)行符號(hào)化?
參考答案:

  • 類型: 數(shù)組越界、插空解包、野指針(EXC_BAD_ACCESS)、主線程卡死(watchdog 機(jī)制)、CPU 超負(fù)荷。
  • 捕獲: 使用 NSSetUncaughtExceptionHandler 捕獲 OC 異常,使用信號(hào)機(jī)制(Signal Handler)捕獲 Mach 異常(如野指針)。
  • 符號(hào)化: 需要 dSYM 符號(hào)表文件,通過 atos 命令行工具或 Xcode 的 Organizer 將內(nèi)存地址翻譯成源碼位置。

Q27:設(shè)計(jì)一個(gè)支持離線存儲(chǔ)、斷點(diǎn)續(xù)傳的大文件下載器。
參考答案: (考察系統(tǒng)設(shè)計(jì)能力)

  • 網(wǎng)絡(luò)層: 使用 URLSession 并配置 background 模式,支持后臺(tái)下載。
  • 斷點(diǎn)續(xù)傳: 利用 resumeData 屬性恢復(fù)下載。
  • 存儲(chǔ): 使用 FileHandle 寫入文件,用數(shù)據(jù)庫記錄下載狀態(tài)(已下載長度、URL、文件哈希)。
  • 狀態(tài)管理: 封裝一個(gè) DownloadManager,使用 OperationQueue 控制并發(fā)數(shù),處理下載、暫停、恢復(fù)、取消邏輯。

11. SwiftUI 與 跨端

Q28:比較 SwiftUI 與 UIKit 的優(yōu)缺點(diǎn),以及在現(xiàn)有 UIKit 項(xiàng)目中如何混用 SwiftUI?
參考答案:

  • SwiftUI: 聲明式 UI、開發(fā)效率高、預(yù)覽方便、與系統(tǒng)特性結(jié)合緊密(如 Dynamic Type),但最低支持 iOS 13,部分復(fù)雜 UI 實(shí)現(xiàn)較困難。
  • 混用: 使用 UIHostingController 將 SwiftUI View 包裝進(jìn) UIKit;使用 UIViewRepresentable 將 UIKit 組件封裝供 SwiftUI 使用。

Q29:Swift 中的 @escaping@autoclosure 關(guān)鍵字是做什么的?
參考答案:

  • @escaping 標(biāo)記閉包在函數(shù)返回之后才被執(zhí)行(如異步網(wǎng)絡(luò)請(qǐng)求的回調(diào))。此時(shí)閉包必須被持有,需要顯式引用 self。
  • @autoclosure 將表達(dá)式自動(dòng)封裝成閉包,延遲執(zhí)行,常用于斷言(assert)函數(shù),避免不必要的表達(dá)式計(jì)算。

12. 綜合與安全

Q30:HTTPS 的握手過程是怎樣的?什么是 SSL Pinning?
參考答案:

  • 握手: 客戶端發(fā)送隨機(jī)數(shù) + 加密套件 -> 服務(wù)端返回證書 + 隨機(jī)數(shù) -> 客戶端驗(yàn)證證書并發(fā)送公鑰加密的預(yù)主密鑰 -> 雙方生成會(huì)話密鑰 -> 開始對(duì)稱加密通信。
  • SSL Pinning: 客戶端預(yù)先綁定服務(wù)端的證書公鑰或證書數(shù)據(jù)。在連接時(shí),不僅驗(yàn)證系統(tǒng)信任鏈,還驗(yàn)證服務(wù)器返回的證書是否與本地硬編碼的證書一致,防止中間人攻擊。

Q31:設(shè)計(jì)一個(gè)組件化方案,如何解決不同模塊之間的依賴和通信?
參考答案:

  • 路由中間件(Mediator): 如 CTMediator(基于 Target-Action),通過 url 或 協(xié)議 進(jìn)行跳轉(zhuǎn),模塊間不直接依賴。
  • 依賴注入: 使用 Swinject 等庫進(jìn)行依賴管理。
  • 協(xié)議式通信: 模塊提供接口協(xié)議,通過中間件注冊(cè)和獲取協(xié)議對(duì)應(yīng)的實(shí)現(xiàn)類。

Q32:你在做性能優(yōu)化時(shí),是如何優(yōu)化列表(TableView/CollectionView)的流暢度的?
參考答案:

  1. 預(yù)判與異步:willDisplayCell 中進(jìn)行圖片的異步解碼和加載。
  2. 避免阻礙主線程: 高度計(jì)算、文本寬高計(jì)算放到后臺(tái)線程。
  3. 減少視圖層級(jí): 扁平化視圖結(jié)構(gòu)。
  4. 避免離屏渲染: 如上文 Q20。
  5. 緩存: 使用 NSCache 緩存圖片或高度。
  6. Diff 算法: iOS 13+ 使用 NSDiffableDataSourceSnapshot 刷新數(shù)據(jù),避免全表刷新。

Q33:簡述 APNs(Apple Push Notification service) 的原理。
參考答案:
設(shè)備請(qǐng)求 Token -> App 將 Token 發(fā)送給業(yè)務(wù)服務(wù)器 -> 業(yè)務(wù)服務(wù)器發(fā)送推送請(qǐng)求(含 Token、Payload)給 APNs -> APNs 查找設(shè)備連接,下發(fā)通知。需確保 Payload 大小不超過限制,并處理好靜默推送的權(quán)限和后臺(tái)喚醒。

Q34:如何檢測(cè)并解決循環(huán)引用(Retain Cycle)?
參考答案:

  • 場(chǎng)景: Delegate(應(yīng)使用 weak)、Block(內(nèi)部引用 self 需使用 [weak self][unowned self])、NSTimer(在 iOS 10+ 使用 block 方式,否則需手動(dòng) invalidate)。
  • 檢測(cè): 使用 Xcode 的 Memory Graph Debugger 或 Instruments 的 Leaks 模板。

Q35:解釋一下 @dynamic 關(guān)鍵字的作用。
參考答案:
@dynamic 告訴編譯器不自動(dòng)生成屬性的 getter 和 setter 實(shí)現(xiàn),通常在運(yùn)行時(shí)動(dòng)態(tài)提供方法實(shí)現(xiàn)時(shí)使用,如 Core Data 的 NSManagedObject 子類屬性。

Q36:對(duì)于 App 被 kill 后收到的推送,點(diǎn)擊圖標(biāo)啟動(dòng)應(yīng)用如何獲取推送內(nèi)容?
參考答案:
AppDelegatedidFinishLaunchingWithOptions 中,通過 launchOptions 字典中的 UIApplicationLaunchOptionsRemoteNotificationKey 獲取遠(yuǎn)程推送信息。如果 App 在后臺(tái)掛起(Suspended)狀態(tài)點(diǎn)擊推送啟動(dòng),也是走此方法。

Q37:如何實(shí)現(xiàn)一個(gè)支持多線程的單例?
參考答案:
Swift 中可以利用 static let 的特性(底層是 dispatch_once)保證線程安全。Objective-C 中通常使用 dispatch_once_t 來保證單例的創(chuàng)建是線程安全的。

Q38:什么是面向協(xié)議編程(Protocol Oriented Programming)?
參考答案:
Swift 的核心思想之一,通過 Protocol 定義一套行為或?qū)傩缘乃{(lán)圖,并通過 Protocol Extension 提供默認(rèn)實(shí)現(xiàn)。它鼓勵(lì)組合而非繼承,使代碼更靈活、更易測(cè)試。

Q39:簡述 Responder Chain(響應(yīng)者鏈)的工作流程。
參考答案:
當(dāng)用戶觸摸屏幕時(shí),系統(tǒng)通過 Hit-Testing 找到第一響應(yīng)者(First Responder),事件沿著響應(yīng)者鏈向上傳遞(如從 view 到 superview 到 viewController 到 window 到 application),直到有對(duì)象處理該事件。常用于自定義事件傳遞和 UI 操作處理。

Q40:假設(shè)現(xiàn)在公司需要將項(xiàng)目遷移到 SwiftUI,請(qǐng)給出一個(gè)分階段的實(shí)施計(jì)劃。
參考答案: (開放性題)

  • 階段一(探索): 在新的、獨(dú)立的模塊或功能中使用 SwiftUI,通過 UIHostingController 嵌入。
  • 階段二(混合): 將一些簡單的、非核心的 UIKit 界面用 SwiftUI 重寫,利用 UIViewRepresentable 處理復(fù)雜的遺留 UIKit 組件。
  • 階段三(遷移): 建立公共的 UI 組件庫(SwiftUI),逐步替換老舊頁面,并確保 iOS 13+ 的用戶體驗(yàn)一致。

當(dāng)然,我們繼續(xù)深入挖掘更多經(jīng)典面試題,以涵蓋更全面的知識(shí)領(lǐng)域,幫助區(qū)分不同級(jí)別的工程師。


繼續(xù):中級(jí)工程師進(jìn)階面試題(續(xù))

9. 數(shù)據(jù)持久化與存儲(chǔ)

Q41:iOS 中的幾種數(shù)據(jù)持久化方式及其適用場(chǎng)景?
參考答案:

  • UserDefaults: 適合存儲(chǔ)輕量級(jí)配置、用戶偏好(如開關(guān)狀態(tài))。
  • Property List(plist): 適合存儲(chǔ)少量、結(jié)構(gòu)簡單的數(shù)據(jù)(如數(shù)組、字典)。
  • 歸檔(NSKeyedArchiver): 可將自定義對(duì)象序列化為二進(jìn)制文件,但靈活性較差。
  • SQLite(通過FMDB或原生C接口): 適合結(jié)構(gòu)化數(shù)據(jù)、復(fù)雜查詢、大量數(shù)據(jù)存儲(chǔ)。
  • Core Data: 對(duì)象圖管理框架,底層可用SQLite,適合模型關(guān)系復(fù)雜、需要Undo/Redo的應(yīng)用。
  • Realm: 第三方移動(dòng)端數(shù)據(jù)庫,性能優(yōu)異,易用性強(qiáng)。

Q42:Core Data 與 SQLite 的本質(zhì)區(qū)別是什么?
參考答案:
Core Data 是一個(gè)對(duì)象圖管理框架,不僅僅是數(shù)據(jù)庫。它負(fù)責(zé)對(duì)象的生命周期、關(guān)系維護(hù)、撤銷管理等,而 SQLite 是純粹的關(guān)系型數(shù)據(jù)庫引擎。Core Data 底層可以使用 SQLite 作為持久化存儲(chǔ),也可以使用 XML、二進(jìn)制等。使用 Core Data 時(shí),開發(fā)者操作的是 NSManagedObject 對(duì)象,無需編寫 SQL 語句。

Q43:什么是數(shù)據(jù)庫遷移(Migration)?在 Core Data 中如何實(shí)現(xiàn)?
參考答案:
當(dāng) Core Data 的模型(xcdatamodeld)發(fā)生改變(如新增字段、修改關(guān)系)時(shí),需要遷移已有數(shù)據(jù)以適應(yīng)新模型。Core Data 提供了輕量級(jí)遷移(Lightweight Migration)——只需設(shè)置選項(xiàng) NSMigratePersistentStoresAutomaticallyOptionYES,系統(tǒng)會(huì)自動(dòng)嘗試推斷映射模型。對(duì)于復(fù)雜遷移,需要自定義 Mapping Model 或編寫遷移代碼。

10. 網(wǎng)絡(luò)與多線程深入

Q44:解釋 DispatchWorkItem 的用途。
參考答案:
DispatchWorkItem 封裝了要執(zhí)行的任務(wù),可以附加到 DispatchQueue 執(zhí)行,并支持取消、等待完成、設(shè)置依賴(通過 notify)等操作。它提供了比直接提交 Block 更多的控制能力,例如可以通過 workItem.cancel() 提前取消尚未執(zhí)行的任務(wù)。

Q45:什么是線程保活?如何實(shí)現(xiàn)一個(gè)常駐后臺(tái)的線程?
參考答案:
線程?;钔ǔS糜谛枰L期監(jiān)聽某個(gè)資源或處理一系列異步任務(wù)的場(chǎng)景(如 AFNetworking 的專用線程)??梢酝ㄟ^在當(dāng)前線程的 RunLoop 中添加一個(gè) Port(如 NSMachPort)并運(yùn)行 RunLoop,使其永不退出。任務(wù)通過 performSelector:onThread: 提交到該線程執(zhí)行。

Q46:iOS 中如何實(shí)現(xiàn)大文件多片并發(fā)上傳/下載?需要考慮哪些因素?
參考答案:
將大文件分割成多個(gè)片段,利用 URLSession 的并發(fā)任務(wù)(URLSessionDownloadTaskURLSessionUploadTask)同時(shí)上傳/下載不同片段。需要考慮:

  • 斷點(diǎn)續(xù)傳: 記錄每個(gè)片段的上傳/下載進(jìn)度,失敗時(shí)重試。
  • 服務(wù)器支持: 服務(wù)器需支持片段合并(如 Content-Range 頭)。
  • 并發(fā)數(shù)控制: 避免過多線程占用帶寬和資源。
  • 完整性校驗(yàn): 下載完成后合并文件,進(jìn)行 MD5 或哈希校驗(yàn)。

11. UI 進(jìn)階與動(dòng)畫

Q47:UIView 動(dòng)畫與 Core Animation 的區(qū)別與聯(lián)系?
參考答案:
UIView 動(dòng)畫是對(duì) Core Animation 的高級(jí)封裝,基于 UIViewanimate 類方法,適用于簡單屬性變化(frame、alpha、transform)。Core Animation(CALayer)更底層,可自定義 Timing、關(guān)鍵幀、復(fù)雜的 3D 變換,且性能更高(操作的是 layer 的模型層和展示層)。UIView 動(dòng)畫底層也是通過 Core Animation 實(shí)現(xiàn),兩者可以混合使用。

Q48:解釋 CALayermask 屬性的作用。
參考答案: mask 是一個(gè) CALayer,它決定了父 Layer 中哪些部分可見。mask 的 alpha 通道決定透明度:mask 中完全不透明部分,父 Layer 內(nèi)容完全可見;mask 中透明部分,父 Layer 內(nèi)容被裁剪。常用于實(shí)現(xiàn)鏤空、漸變裁剪等效果。

Q49:如何實(shí)現(xiàn)一個(gè)平滑的抽屜菜單(Side Menu)交互?
參考答案: 通常通過 UIPanGestureRecognizerUIViewPropertyAnimator 實(shí)現(xiàn)。手勢(shì)過程中實(shí)時(shí)更新視圖的 frame 或 transform,配合彈簧動(dòng)畫(spring)實(shí)現(xiàn)彈性效果。需要注意處理邊緣滑回、手勢(shì)沖突(與 ScrollView 共存)、狀態(tài)恢復(fù)(打開/關(guān)閉)以及性能優(yōu)化(避免離屏渲染)。

12. 第三方庫原理

Q50:AFNetworking / Alamofire 是如何實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的?
參考答案: 它們是對(duì) NSURLSession 的封裝,通過 NSURLSessionDataTask 執(zhí)行請(qǐng)求。AFNetworking 提供了序列化、驗(yàn)證、安全策略等功能,通過組合 NSOperation 管理請(qǐng)求,支持請(qǐng)求隊(duì)列、依賴關(guān)系。Alamofire 則基于 Swift 的閉包和協(xié)議,提供了鏈?zhǔn)?API,并內(nèi)置了 RequestAdapterRequestRetrier 等擴(kuò)展機(jī)制。

Q51:SDWebImage / Kingfisher 的緩存策略是怎樣的?
參考答案: 一般采取兩級(jí)緩存:內(nèi)存緩存(NSCache)和磁盤緩存(文件系統(tǒng))。

  • 讀取流程: 先查內(nèi)存緩存 -> 若無,則查磁盤緩存 -> 若無,則發(fā)起網(wǎng)絡(luò)下載。
  • 下載完成后: 解碼圖片,先存入內(nèi)存,再異步存入磁盤。
  • 緩存清理: 內(nèi)存緩存收到內(nèi)存警告時(shí)自動(dòng)清空;磁盤緩存通過 LRU(最近最少使用)算法限制大小和天數(shù)。

Q52:ReactiveCocoa / RxSwift / Combine 的核心思想是什么?
參考答案: 它們都基于響應(yīng)式編程范式,核心是“數(shù)據(jù)流”和“觀察者模式”。通過將事件、數(shù)據(jù)變化抽象為“信號(hào)流”(Signal / Observable),開發(fā)者可以使用操作符(map、filter、merge)對(duì)異步事件進(jìn)行組合和變換,使代碼更簡潔、更易測(cè)試。Combine 是蘋果官方的響應(yīng)式框架,深度集成 Swift 語言,支持 backpressure 和類型安全。


三、高級(jí)工程師深度面試題(續(xù))

13. 底層原理與逆向工程

Q53:解釋 Mach-O 文件格式,App 啟動(dòng)時(shí) dyld 是如何加載的?
參考答案: Mach-O 是 iOS/macOS 的可執(zhí)行文件格式,包含 Header、Load Commands、Data(多個(gè)段 Segment,如 __TEXT, __DATA)。啟動(dòng)時(shí),內(nèi)核加載 dyld(動(dòng)態(tài)鏈接器),dyld 負(fù)責(zé):

  1. 解析 Mach-O 依賴的動(dòng)態(tài)庫。
  2. 執(zhí)行 Rebase(修正內(nèi)部指針)和 Bind(綁定外部符號(hào))。
  3. 加載所有依賴庫。
  4. 執(zhí)行初始化方法(+load、C++ 靜態(tài)構(gòu)造函數(shù))。
  5. 最后調(diào)用 main()。

Q54:什么是 Fishhook?它的原理是什么?
參考答案: Fishhook 是一個(gè)第三方庫,用于動(dòng)態(tài)修改 C 語言符號(hào)(如 open、close)的實(shí)現(xiàn)。原理:Mach-O 的 __DATA 段中有兩個(gè)表——Lazy Symbol Pointers 和 Non-Lazy Symbol Pointers,存儲(chǔ)了外部函數(shù)的地址。Fishhook 通過修改這些指針,使其指向自定義的函數(shù),從而實(shí)現(xiàn) hook。

Q55:如何防護(hù) iOS App 被注入動(dòng)態(tài)庫或進(jìn)行 Method Swizzling?
參考答案:

  • 反注入: 編譯設(shè)置 OTHER_LDFLAGS 添加 -Wl,-sectcreate,__RESTRICT,__restrict,/dev/null 生成 __RESTRICT 段,使 dyld 禁止加載第三方注入庫。
  • 防護(hù) Method Swizzling: 在關(guān)鍵類的方法實(shí)現(xiàn)中,通過比較 IMP 是否被篡改進(jìn)行校驗(yàn);使用 fishhook 防護(hù)常見的 hook 函數(shù)(如 method_exchangeImplementations)。
  • 字符串加密: 避免明文字符串暴露 API 或關(guān)鍵類名。

14. 性能優(yōu)化進(jìn)階

Q56:如何監(jiān)控和優(yōu)化 App 的 CPU 使用率和耗電量?
參考答案:

  • 監(jiān)控: 使用 Instruments 的 Energy Log 和 CPU Counters 檢測(cè)高耗電操作(如定位、后臺(tái)網(wǎng)絡(luò)喚醒、高頻率喚醒 CPU)。
  • 優(yōu)化:
    • 避免輪詢,使用推送代替。
    • 合并網(wǎng)絡(luò)請(qǐng)求,減少網(wǎng)絡(luò)喚醒次數(shù)。
    • 謹(jǐn)慎使用高精度定時(shí)器(CADisplayLink 應(yīng)設(shè)置 preferredFramesPerSecond)。
    • 及時(shí)釋放無用資源,避免后臺(tái)持續(xù)運(yùn)行。

Q57:什么是內(nèi)存映射文件(Memory-mapped File)?在 iOS 中如何應(yīng)用?
參考答案: 內(nèi)存映射文件將文件內(nèi)容映射到進(jìn)程的虛擬內(nèi)存空間,通過指針直接讀寫文件,避免了傳統(tǒng)的 read/write 系統(tǒng)調(diào)用和緩沖區(qū)拷貝。iOS 中可以使用 mmap 函數(shù),常用于大文件隨機(jī)訪問(如數(shù)據(jù)庫引擎、圖片加載框架)。Core Data 的 WAL 模式也使用了類似技術(shù)。

Q58:解釋一下 App 的預(yù)熱(Warm Launch)與冷啟動(dòng)(Cold Launch)的區(qū)別。
參考答案: 冷啟動(dòng)是指 App 進(jìn)程不在內(nèi)存中,從頭開始啟動(dòng),包括加載內(nèi)核、dyld、應(yīng)用初始化等完整過程。預(yù)熱是指 App 進(jìn)程已在后臺(tái)掛起,用戶重新切換回前臺(tái),此時(shí)只需恢復(fù)進(jìn)程、執(zhí)行一些 resume 操作,速度快很多。優(yōu)化的重點(diǎn)是冷啟動(dòng)。

15. 架構(gòu)與設(shè)計(jì)思想

Q59:你如何理解“依賴注入”(Dependency Injection)?在 iOS 中如何實(shí)現(xiàn)?
參考答案: 依賴注入是一種設(shè)計(jì)模式,將對(duì)象的依賴關(guān)系從內(nèi)部創(chuàng)建轉(zhuǎn)移到外部傳入,提高模塊的松耦合性和可測(cè)試性。實(shí)現(xiàn)方式:

  • 構(gòu)造器注入: 通過 init 方法傳入依賴。
  • 屬性注入: 通過公開屬性設(shè)置依賴(常用)。
  • 方法注入: 通過方法參數(shù)傳遞。
  • 第三方庫: 如 Swinject 通過容器自動(dòng)解析依賴。

Q60:請(qǐng)介紹一個(gè)你設(shè)計(jì)的組件化方案,包括模塊劃分原則、通訊機(jī)制、以及如何解決模塊間資源共享。
參考答案: (開放設(shè)計(jì)題)

  • 劃分原則: 按業(yè)務(wù)線劃分(如首頁、社區(qū)、我的),基礎(chǔ)組件(網(wǎng)絡(luò)、圖片、數(shù)據(jù)庫)單獨(dú)成庫。
  • 通訊機(jī)制: 采用中間件(Mediator)模式,每個(gè)業(yè)務(wù)模塊實(shí)現(xiàn)一個(gè)公開的 Protocol,中間件維護(hù)模塊與 Protocol 的映射。調(diào)用方通過 Protocol 獲取服務(wù)實(shí)例。
  • 資源共享: 建立公共 UI 組件庫、資源文件統(tǒng)一管理,使用 CocoaPods 或 Swift Package Manager 管理依賴,避免重復(fù)資源。

Q61:如何確保 App 在不同網(wǎng)絡(luò)環(huán)境下的數(shù)據(jù)一致性(例如弱網(wǎng)、斷網(wǎng))?
參考答案:

  • 緩存策略: 采用“先讀緩存,再請(qǐng)求網(wǎng)絡(luò)”的模式,網(wǎng)絡(luò)請(qǐng)求失敗時(shí)展示緩存數(shù)據(jù)。
  • 請(qǐng)求重試: 使用指數(shù)退避算法(Exponential Backoff)重試失敗請(qǐng)求。
  • 本地持久化: 將用戶操作(如評(píng)論、點(diǎn)贊)先記錄到本地?cái)?shù)據(jù)庫,再嘗試同步到服務(wù)器,解決“寫”操作的一致性。
  • 狀態(tài)同步: 使用 WebSocket 或長輪詢,服務(wù)器推送狀態(tài)變更,避免客戶端頻繁拉取。

16. 安全與逆向

Q62:iOS 應(yīng)用如何防止二次打包(重簽名)?
參考答案:

  • 校驗(yàn) Bundle ID 和證書信息: 在代碼中檢查 [[NSBundle mainBundle] bundleIdentifier] 是否與預(yù)期一致,使用 getenv 檢查 DYLD_INSERT_LIBRARIES 是否為空。
  • 校驗(yàn)簽名: 通過 MobileCoreServices 或 Security.framework 驗(yàn)證可執(zhí)行文件的簽名是否匹配。
  • 校驗(yàn)文件哈希: 在關(guān)鍵資源文件(如圖片、配置文件)計(jì)算哈希值,對(duì)比是否被篡改。
  • 服務(wù)器驗(yàn)證: 將設(shè)備信息與應(yīng)用簽名發(fā)送到服務(wù)器,服務(wù)器驗(yàn)證簽名合法性。

Q63:什么是代碼混淆?常用的混淆工具有哪些?
參考答案: 代碼混淆是改變程序結(jié)構(gòu)和邏輯,使其難以被逆向工程師理解,但不影響程序功能。常見的混淆技術(shù)包括:控制流平坦化、字符串加密、符號(hào)名稱混淆(如將方法名替換為無意義字符)。iOS 常用的工具有:Obfuscator-LLVM(基于編譯器的混淆)、class-dump 防護(hù)(通過去除符號(hào)表)、自定義腳本對(duì)關(guān)鍵字符串進(jìn)行 XOR 加密。

17. 多線程與并發(fā)高級(jí)

Q64:解釋 Dispatch Barrier 的用途。
參考答案: Dispatch Barrier 用于在并發(fā)隊(duì)列中創(chuàng)建一個(gè)同步點(diǎn)。提交到隊(duì)列的 barrier 任務(wù)會(huì)等待隊(duì)列中所有已提交的任務(wù)完成,然后獨(dú)占執(zhí)行(期間其他任務(wù)不被調(diào)度),執(zhí)行完畢后隊(duì)列恢復(fù)正常并發(fā)。常用于實(shí)現(xiàn)多讀單寫(Readers-Writers)模式,如對(duì)共享數(shù)據(jù)的讀寫安全保護(hù)。

Q65:os_unfair_lockNSLock、@synchronized 的區(qū)別是什么?
參考答案:

  • os_unfair_lock 是替代 OSSpinLock 的低級(jí)鎖,不會(huì)出現(xiàn)優(yōu)先級(jí)反轉(zhuǎn)問題,適合輕量級(jí)鎖,從用戶態(tài)陷入內(nèi)核態(tài),性能較好。
  • NSLock 是對(duì) pthread_mutex 的封裝,提供了 tryLock 等方法,支持條件鎖(NSConditionLock)。
  • @synchronized 使用遞歸鎖(recursive_mutex),基于對(duì)象指針進(jìn)行加鎖,異常安全,但性能較差,因?yàn)樗鼤?huì)生成隱藏的異常處理代碼。

18. 新技術(shù)與趨勢(shì)

Q66:Swift 并發(fā)(Swift Concurrency)中的 async/await 是如何工作的?
參考答案: async/await 是 Swift 5.5 引入的異步編程模型。async 標(biāo)記的函數(shù)可以掛起,await 用于等待異步操作完成。底層基于協(xié)程,編譯器將異步函數(shù)轉(zhuǎn)換為帶有回調(diào)的狀態(tài)機(jī),通過協(xié)作式調(diào)度(由運(yùn)行時(shí)管理)實(shí)現(xiàn)非阻塞等待,避免了傳統(tǒng)回調(diào)地獄和線程開銷。

Q67:解釋 Actor 在 Swift 并發(fā)中的作用。
參考答案: Actor 是一種保護(hù)可變狀態(tài)免于數(shù)據(jù)競(jìng)爭的引用類型。它通過互斥訪問來同步對(duì)內(nèi)部狀態(tài)的訪問:同一時(shí)間只有一個(gè)任務(wù)可以訪問 actor 的內(nèi)部狀態(tài),從而避免了顯式加鎖。對(duì) actor 方法的調(diào)用是異步的,需要使用 await 調(diào)用。

Q68:什么是 SwiftUI 的 @State@Binding?
參考答案:

  • @State 用于在視圖內(nèi)部聲明可變狀態(tài),當(dāng)值改變時(shí),視圖會(huì)自動(dòng)重新計(jì)算 body。它是視圖的私有數(shù)據(jù),由 SwiftUI 管理存儲(chǔ)。
  • @Binding 用于在父子視圖間共享數(shù)據(jù),它允許子視圖讀寫父視圖的 @State,而不需要直接持有數(shù)據(jù)。

Q69:請(qǐng)簡述 Swift Package Manager 與 CocoaPods 的優(yōu)缺點(diǎn)。
參考答案:

  • SPM: 蘋果官方工具,深度集成 Xcode,支持二進(jìn)制分發(fā),自動(dòng)管理依賴,無需安裝額外工具。但早期不支持資源文件和 UIKit 等框架的復(fù)雜配置,現(xiàn)在已逐漸完善。
  • CocoaPods: 第三方工具,生態(tài)成熟,支持復(fù)雜的庫配置、資源文件、動(dòng)態(tài)庫/靜態(tài)庫混用。缺點(diǎn)是需要安裝 gem,使用 pod install 生成工作區(qū),可能增加構(gòu)建時(shí)間。

19. 調(diào)試與測(cè)試

Q70:什么是 LLDB?常用命令有哪些?
參考答案: LLDB 是 Xcode 的底層調(diào)試器。常用命令:

  • po:打印對(duì)象描述。
  • p:打印原始類型值。
  • expr:執(zhí)行表達(dá)式。
  • bt:打印當(dāng)前線程的堆棧。
  • breakpoint set -n methodName:設(shè)置符號(hào)斷點(diǎn)。
  • image lookup -address 0x...:根據(jù)地址查找符號(hào)。

Q71:如何編寫單元測(cè)試和 UI 測(cè)試?Mock 和 Stub 的區(qū)別是什么?
參考答案:

  • 單元測(cè)試: 使用 XCTest 框架,測(cè)試獨(dú)立模塊的功能。常用斷言如 XCTAssertEqualXCTAssertNotNil。
  • UI 測(cè)試: 使用 XCUITest,通過錄制或編寫代碼模擬用戶交互,驗(yàn)證 UI 狀態(tài)。
  • Mock: 模擬對(duì)象,用于驗(yàn)證被測(cè)試對(duì)象與 Mock 的交互(如是否調(diào)用了特定方法)。
  • Stub: 提供預(yù)設(shè)的返回值或行為,用于控制被測(cè)試對(duì)象的外部依賴,但不驗(yàn)證交互。

Q72:如何檢測(cè)并解決主線程卡頓?
參考答案:

  • 檢測(cè): 使用 Ping 機(jī)制(子線程監(jiān)測(cè)主線程 RunLoop 是否響應(yīng)),或通過 CADisplayLink 檢測(cè)丟幀率。可使用第三方庫如 KSCrash 或自己實(shí)現(xiàn)卡頓監(jiān)控。
  • 解決: 將耗時(shí)操作(圖片解碼、JSON 解析、文件讀寫)移到后臺(tái)線程;優(yōu)化 UI 布局,減少離屏渲染;避免主線程執(zhí)行同步網(wǎng)絡(luò)請(qǐng)求。

四、拓展與綜合題(覆蓋全級(jí)別)

20. 編碼與實(shí)戰(zhàn)

Q73:如何實(shí)現(xiàn)一個(gè)倒計(jì)時(shí)按鈕(獲取驗(yàn)證碼后倒計(jì)時(shí)60s)?需要考慮哪些細(xì)節(jié)?
參考答案:

  • 使用 TimerDispatchSourceTimer 每秒更新 UI。
  • 注意定時(shí)器的循環(huán)引用(使用 [weak self])。
  • 倒計(jì)時(shí)期間按鈕不可點(diǎn)擊,文字顯示“剩余xx秒”。
  • 退后臺(tái)時(shí)暫停計(jì)時(shí),回到前臺(tái)繼續(xù)(或重置),或使用 BackgroundTask 保證后臺(tái)繼續(xù)(視需求)。
  • 釋放定時(shí)器(invalidate)避免內(nèi)存泄漏。

Q74:簡述 KVO 的實(shí)現(xiàn)原理,以及如何手動(dòng)觸發(fā) KVO?
參考答案: KVO 基于運(yùn)行時(shí)動(dòng)態(tài)生成子類(NSKVONotifying_XXX),重寫被觀察屬性的 setter 方法,在 setter 中插入 willChangeValueForKeydidChangeValueForKey 方法。手動(dòng)觸發(fā):調(diào)用 willChangeValueForKeydidChangeValueForKey 方法即可,即使屬性值未改變也能觸發(fā)觀察者。

Q75:什么是 @dynamic@synthesize?
參考答案:

  • @synthesize:告訴編譯器自動(dòng)生成屬性的 getter 和 setter 以及實(shí)例變量(默認(rèn)行為)。
  • @dynamic:告訴編譯器不自動(dòng)生成,開發(fā)者會(huì)自己提供(或運(yùn)行時(shí)提供),常用于 Core Data 的 NSManagedObject。

Q76:如何實(shí)現(xiàn)一個(gè)自定義的線程安全數(shù)組?
參考答案: 可以使用并發(fā)隊(duì)列 + 屏障(Dispatch Barrier)實(shí)現(xiàn)多讀單寫。

class ThreadSafeArray<Element> {
    private var array: [Element] = []
    private let queue = DispatchQueue(label: "com.example.threadsafe", attributes: .concurrent)

    func read(at index: Int) -> Element? {
        return queue.sync {
            return array.indices.contains(index) ? array[index] : nil
        }
    }

    func write(_ element: Element, at index: Int) {
        queue.async(flags: .barrier) { [weak self] in
            guard let self = self else { return }
            if self.array.indices.contains(index) {
                self.array[index] = element
            }
        }
    }
}

Q77:如何在 Swift 中實(shí)現(xiàn)一個(gè)單例模式?
參考答案:

class MySingleton {
    static let shared = MySingleton()
    private init() {} // 私有化初始化
}

Swift 的 static let 自動(dòng)保證了線程安全和一次性初始化。

Q78:如何實(shí)現(xiàn)一個(gè)深拷貝(Deep Copy)?
參考答案: 實(shí)現(xiàn) NSCopying 協(xié)議(對(duì)于 Objective-C 對(duì)象),對(duì)于 Swift 的類,可以自定義一個(gè) copy() 方法,遞歸復(fù)制所有成員。對(duì)于結(jié)構(gòu)體和集合類型,直接使用 let copy = original 是深拷貝嗎?集合(如 Array)在 Swift 中是值類型,元素是引用類型時(shí),只是復(fù)制了引用(淺拷貝)。要實(shí)現(xiàn)深拷貝,需遍歷元素并逐個(gè)復(fù)制。

Q79:解釋一下 Bitcode 的作用。
參考答案: Bitcode 是 LLVM 編譯器的中間代碼(IR,Intermediate Representation)。當(dāng)開發(fā)者上傳包含 Bitcode 的 App 到 App Store Connect,蘋果可以在后臺(tái)根據(jù) Bitcode 重新優(yōu)化生成最終的可執(zhí)行文件,以適應(yīng)未來新的處理器架構(gòu)或優(yōu)化性能。從 Xcode 14 開始,Bitcode 已廢棄,不再需要。

Q80:什么是 App Thinning?它包括哪幾種優(yōu)化技術(shù)?
參考答案: App Thinning 是蘋果提供的一套優(yōu)化技術(shù),旨在減少用戶下載和安裝 App 的大小。包括:

  • Slicing: App Store 根據(jù)用戶的設(shè)備型號(hào)(CPU架構(gòu)、屏幕分辨率)只分發(fā)對(duì)應(yīng)的可執(zhí)行文件和資源。
  • Bitcode: 蘋果后臺(tái)重新編譯優(yōu)化。
  • On-Demand Resources: 按需下載資源,如圖片、關(guān)卡數(shù)據(jù),在應(yīng)用內(nèi)動(dòng)態(tài)下載和刪除。

21. 系統(tǒng)框架與功能

Q81:如何使用 Core Location 進(jìn)行后臺(tái)定位?需要注意哪些權(quán)限和配置?
參考答案: 需要在 Info.plist 中添加 NSLocationAlwaysAndWhenInUseUsageDescriptionUIBackgroundModes 中的 location。請(qǐng)求授權(quán)時(shí)使用 requestAlwaysAuthorization()。為了節(jié)省電量,建議在后臺(tái)定位時(shí)降低精度(desiredAccuracy)和距離過濾器(distanceFilter),或使用訪客性定位(allowsBackgroundLocationUpdates = true 并配合 pausesLocationUpdatesAutomatically)。

Q82:什么是 Universal Links?它解決了什么問題?
參考答案: Universal Links 是 iOS 9 引入的深度鏈接技術(shù),允許通過標(biāo)準(zhǔn)的 HTTP/HTTPS 鏈接直接打開 App(若已安裝),否則在瀏覽器中打開網(wǎng)頁。它解決了傳統(tǒng) URL Scheme 的安全隱患(可被任意 App 偽造調(diào)用)和未安裝時(shí)的回退問題。配置需要在蘋果開發(fā)者后臺(tái)關(guān)聯(lián)域名,并在服務(wù)器上傳 apple-app-site-association 文件。

Q83:如何實(shí)現(xiàn) 3D Touch / Haptic Touch 的快捷菜單(Home Screen Quick Actions)?
參考答案: 在 App 的 Info.plist 中添加 UIApplicationShortcutItems 數(shù)組,配置每個(gè) item 的標(biāo)題、圖標(biāo)和 userInfo。也可以在運(yùn)行時(shí)通過 UIApplicationShortcutItem 動(dòng)態(tài)添加/更新。用戶點(diǎn)擊后,AppDelegate 的 application(_:performActionFor:completionHandler:) 會(huì)收到回調(diào)。

Q84:如何實(shí)現(xiàn)音頻后臺(tái)播放?
參考答案: 設(shè)置 AudioSession 類別為 AVAudioSessionCategoryPlayback,并在 Capabilities 中開啟 Background Modes 的 Audio, AirPlay, and Picture in Picture。使用 AVAudioPlayerAVPlayer 播放時(shí),應(yīng)用退到后臺(tái)仍能繼續(xù)播放。

22. 設(shè)計(jì)模式與原則

Q85:解釋 SOLID 原則在 iOS 開發(fā)中的應(yīng)用。
參考答案:

  • 單一職責(zé)原則: 一個(gè)類只負(fù)責(zé)一項(xiàng)職責(zé),例如 ViewController 不應(yīng)同時(shí)負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求和數(shù)據(jù)解析。
  • 開閉原則: 對(duì)擴(kuò)展開放,對(duì)修改關(guān)閉。如通過 Protocol 和依賴注入,添加新功能時(shí)不修改原有代碼。
  • 里氏替換原則: 子類應(yīng)能替換父類并保持行為一致。
  • 接口隔離原則: 使用專門的協(xié)議代替龐大的協(xié)議,避免實(shí)現(xiàn)不需要的方法。
  • 依賴反轉(zhuǎn)原則: 依賴抽象而非具體實(shí)現(xiàn),如使用依賴注入。

Q86:什么是適配器模式?在 iOS 中如何應(yīng)用?
參考答案: 適配器模式將不兼容的接口轉(zhuǎn)換為可兼容的接口。例如,將第三方庫的接口適配成項(xiàng)目內(nèi)統(tǒng)一的數(shù)據(jù)源格式。在 iOS 中,常用的場(chǎng)景是使用分類(Category)為系統(tǒng)類添加方法,或者將不同的數(shù)據(jù)模型適配成 UITableViewDataSource 所需的統(tǒng)一格式。

23. 算法與數(shù)據(jù)結(jié)構(gòu)(基礎(chǔ))

Q87:如何反轉(zhuǎn)一個(gè)鏈表?
參考答案: 使用迭代法:定義三個(gè)指針 prev、current、next,遍歷鏈表,逐個(gè)反轉(zhuǎn)方向。

func reverseList(_ head: ListNode?) -> ListNode? {
    var prev: ListNode? = nil
    var curr = head
    while curr != nil {
        let next = curr?.next
        curr?.next = prev
        prev = curr
        curr = next
    }
    return prev
}

Q88:如何判斷一個(gè)字符串是否是回文字符串?
參考答案: 雙指針法:從字符串兩端向中間比較字符(忽略大小寫和非字母數(shù)字)。

func isPalindrome(_ s: String) -> Bool {
    let chars = Array(s.lowercased())
    var left = 0, right = chars.count - 1
    while left < right {
        if !chars[left].isLetter && !chars[left].isNumber {
            left += 1
            continue
        }
        if !chars[right].isLetter && !chars[right].isNumber {
            right -= 1
            continue
        }
        if chars[left] != chars[right] {
            return false
        }
        left += 1
        right -= 1
    }
    return true
}

24. 系統(tǒng)設(shè)計(jì)題

Q89:設(shè)計(jì)一個(gè)類似微信的朋友圈功能,需要考慮哪些模塊?
參考答案: (開放性設(shè)計(jì)題)

  • 數(shù)據(jù)模型: 用戶、動(dòng)態(tài)(文字、圖片、視頻)、評(píng)論、點(diǎn)贊。
  • 存儲(chǔ): 本地緩存(Core Data/Realm)+ 服務(wù)器數(shù)據(jù)庫。
  • 網(wǎng)絡(luò): 分頁拉?。ㄏ吕⑿隆⑸侠虞d),上傳發(fā)布(圖片/視頻預(yù)處理)。
  • UI: 多類型 Cell、自適應(yīng)高度、富文本展示。
  • 交互: 評(píng)論/點(diǎn)贊更新(局部刷新)、異步發(fā)布。
  • 推送: 有新評(píng)論/點(diǎn)贊時(shí)推送通知。

Q90:設(shè)計(jì)一個(gè)支持離線緩存和手動(dòng)清理緩存的圖片加載庫。
參考答案:

  • 接口: 提供 loadImage(url: completion:)clearCache()。
  • 緩存策略: 內(nèi)存緩存(NSCache) + 磁盤緩存(文件系統(tǒng))。磁盤緩存使用 LRU 算法,限制大小。
  • 下載器: 使用 URLSession,支持請(qǐng)求合并(相同 URL 只下載一次),并實(shí)現(xiàn)優(yōu)先級(jí)。
  • 解碼: 圖片解碼放到后臺(tái)線程,避免阻塞主線程。
  • 擴(kuò)展性: 支持自定義緩存 key(如 URL 轉(zhuǎn)換為 MD5)、支持下載進(jìn)度回調(diào)。

25. 面試中常見行為問題(軟技能)

雖然這是技術(shù)面,但高級(jí)職位常會(huì)穿插這些問題以評(píng)估綜合素質(zhì)。

Q91:描述一次你解決過的棘手 Bug 的經(jīng)歷。
期望回答: 使用 STAR 法則(情境-任務(wù)-行動(dòng)-結(jié)果),例如:遇到了一個(gè)偶現(xiàn)的野指針崩潰,通過啟用 Zombie Objects、分析堆棧、最終定位到是異步回調(diào)后對(duì)象已被釋放,通過修改生命周期管理解決。

Q92:如果產(chǎn)品經(jīng)理要求實(shí)現(xiàn)一個(gè)技術(shù)上不可行的需求,你怎么辦?
期望回答: 先傾聽并理解需求的真正目的,然后提出技術(shù)限制和替代方案,與產(chǎn)品經(jīng)理協(xié)商一個(gè)折中方案,用數(shù)據(jù)和原型證明可行性,最終達(dá)成共識(shí)。

Q93:你是如何保持技術(shù)更新的?
期望回答: 閱讀官方文檔(WWDC 視頻)、關(guān)注知名技術(shù)博客(如 NSHipster)、參與 GitHub 開源項(xiàng)目、定期學(xué)習(xí) Swift 新特性、參加技術(shù)會(huì)議等。

Q94:你覺得自己最大的技術(shù)優(yōu)勢(shì)是什么?
期望回答: 結(jié)合崗位要求,例如:“我擅長性能優(yōu)化,之前通過 Instruments 分析將列表滾動(dòng)幀率從 40fps 提升到 60fps?!被蛘摺拔覠嶂杂诩軜?gòu)設(shè)計(jì),主導(dǎo)過項(xiàng)目的組件化改造?!?/p>

Q95:你對(duì)代碼重構(gòu)和遺留代碼的態(tài)度是什么?
期望回答: 主張漸進(jìn)式重構(gòu),優(yōu)先編寫測(cè)試保證功能,逐步替換老舊模塊,避免“大爆炸”式重寫導(dǎo)致風(fēng)險(xiǎn)。

26. 開放性問題

Q96:如果讓你設(shè)計(jì)一個(gè)日志收集框架,你會(huì)怎么設(shè)計(jì)?
參考答案: 考慮模塊化:

  • 日志級(jí)別: Debug、Info、Warning、Error,可配置輸出級(jí)別。
  • 日志格式: 時(shí)間戳、線程、文件名/行號(hào)、自定義 tag。
  • 輸出方式: 支持控制臺(tái)輸出、文件輸出、網(wǎng)絡(luò)上報(bào)。
  • 性能: 異步寫入(dispatch_io 或 dispatch_async),避免影響主線程。
  • 輪轉(zhuǎn)策略: 日志文件按大小/日期滾動(dòng),自動(dòng)清理過期日志。

Q97:如何監(jiān)控 App 的網(wǎng)絡(luò)請(qǐng)求耗時(shí)和成功率?
參考答案: 使用 NSURLProtocolURLSession 的代理攔截請(qǐng)求,記錄開始時(shí)間和結(jié)束時(shí)間,計(jì)算耗時(shí),判斷 HTTP 狀態(tài)碼和 error。也可以利用 Network.framework 或第三方庫(如 Alamofire 的 EventMonitor)。將數(shù)據(jù)上報(bào)到后臺(tái)進(jìn)行分析。

Q98:解釋一下 Swift 中的 some 關(guān)鍵字(Opaque Type)的作用。
參考答案: some 用于返回一個(gè)不透明類型,它告訴編譯器“這個(gè)方法返回一個(gè)遵循某個(gè)協(xié)議的具體類型,但調(diào)用者不需要知道具體是什么”。它結(jié)合了泛型和協(xié)議,保留了類型信息(相比協(xié)議類型),有利于編譯器優(yōu)化,常用于 SwiftUI 的 View 類型。

Q99:Swift 中 #available@available 的區(qū)別?
參考答案: @available 是屬性,用于聲明類型或方法的可用性(如 @available(iOS 13, *))。#available 是條件語句,用于運(yùn)行時(shí)檢查當(dāng)前系統(tǒng)版本是否滿足要求(如 if #available(iOS 14, *) { })。

Q100:作為 iOS 開發(fā)者,你未來 3 年的職業(yè)規(guī)劃是什么?
期望回答: 根據(jù)面試級(jí)別不同回答,如初級(jí)工程師希望成為中級(jí),中級(jí)希望成為高級(jí)/架構(gòu)師,高級(jí)希望成為技術(shù) leader 或深耕某一領(lǐng)域(如音視頻、跨端)。表達(dá)出持續(xù)學(xué)習(xí)和貢獻(xiàn)的熱情。

總結(jié)表格:崗位技能要求概覽

崗位級(jí)別 核心考察點(diǎn) 典型問題標(biāo)簽 面試官關(guān)注的行為
初級(jí) 語言基礎(chǔ)、UIKit基礎(chǔ)、版本控制、調(diào)試 可選型、Frame/Bounds、生命周期 是否能獨(dú)立完成功能,基礎(chǔ)知識(shí)是否牢固
中級(jí) 多線程、內(nèi)存管理、架構(gòu)模式、Runtime Block循環(huán)引用、MVVM、GCD死鎖 是否考慮過性能、代碼復(fù)用,是否理解底層原理
高級(jí) 性能調(diào)優(yōu)、組件化、底層原理、安全 啟動(dòng)優(yōu)化、RunLoop、Swizzling 是否具備技術(shù)前瞻性,能否解決疑難雜癥,能否做技術(shù)決策

結(jié)尾

至此,我們已整理出 100 道涵蓋初級(jí)、中級(jí)、高級(jí)的經(jīng)典 iOS 面試題及答案。這些題目既有基礎(chǔ)概念的考察,也有深度原理的挖掘,希望能幫助面試官全面評(píng)估候選人的能力,也助力求職者查漏補(bǔ)缺。在真實(shí)面試中,建議根據(jù)候選人的表現(xiàn)靈活追問,考察其解決問題的思路和溝通能力。祝面試順利!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容