??Swift 語言特性??:請解釋一下?struct
和?class
的主要區別。
特性?? | ??struct (值類型)?? | ??class (引用類型)?? |
---|---|---|
??類型本質?? | 值類型 (復制時創建獨立副本) | 引用類型 (復制時共享同一實例) |
??內存分配?? | 通常在棧上 (更快速) | 在堆上 (需要ARC管理) |
??可變性?? | 默認不可變 (需? | 默認可變 |
??繼承?? | 不支持繼承 | 支持單繼承 |
??析構器?? | 無? | 有? |
??線程安全?? | 天然線程安全 (獨立副本) | 需手動同步 (多線程訪問同一實例可能沖突) |
??引用計數?? | 無 | 依賴ARC管理內存 |
??
內存管理??:談談你對 ARC(自動引用計數)的理解。什么是強引用循環?如何避免?
Swift 在編譯時自動插入?retain
(增加引用計數)和?release
(減少引用計數)指令,通過??跟蹤對象的引用關系??自動管理內存生命周期。
解釋?weak
和?unowned
的底層區別??:
weak
通過額外??側表(Side Table)?? 實現自動置?nil
,unowned
直接訪問原始指針。.
??生命周期??:描述一下?UIViewController
的視圖生命周期(例如?viewDidLoad
,?viewWillAppear
,?viewDidLayoutSubviews
等)。在哪個方法里更新視圖的布局或幀是安全的?
loadView() 創建視圖層次的根視圖
viewDidLoad()視圖首次加載到內存
??viewWillAppear(_:)視圖即將出現
viewDidAppear(_:)視圖完成顯示
viewWillDisappear(_:)視圖即將離開屏幕
viewDidDisappear(_:)視圖已經離開屏幕
??viewWillLayoutSubviews()
視圖??即將計算子視圖布局
??viewDidLayoutSubviews()
視圖??已完成子視圖布局計算??(frame
已確定)
我們在viewDidLayoutSubviews()中更新視圖布局或者幀是最安全的
??多線程??:DispatchQueue.main.async
和?DispatchQueue.global().async
分別有什么作用?為什么更新UI必須在主隊列進行?
DispatchQueue.main.async:從非主線程切換到主線程,確保UI操作在主線程執行
?DispatchQueue.global().async
的作用:全局隊列,是一個并發隊列
UIKit 和 CoreAnimation 的底層代碼??未加鎖??(鎖會降低性能),同一時間只允許??主線程??修改 UI 元素。
Objective-C 中Category
和Extension
的區別是什么?Category 能否添加成員變量?如果不能,如何間接實現 “添加屬性” 的效果?(考察 runtime 關聯對象的理解)
category分類
用于給已經存在的類添加新方法,不能添加新的成員變量,可以有單獨的文件,經常用于講將一個龐大的類拆分為多個模塊
類擴展
本質上是類的匿名分類,只能定義在類的實現文件中,可以添加私有成員變量,方法和屬性
Category不能添加成員變量,因為oc的類在編譯的時候就會確定內存布局,故無法添加
可以使用runtime關聯對象實現,原理是將一個對象和另一個對象關聯起來,可以達到添加屬性的效果
關聯對象本質上是通過 Runtime 函數,將一個對象(值)與另一個對象(宿主)建立關聯關系,并通過唯一的 key 來標識這種關聯。這種關聯關系會被系統管理,當宿主對象被銷毀時,關聯對象也可以被自動清理。
Swift 的Optional
(可選類型)是如何解決空指針問題的?請解釋?
、!
、guard let
、if let
的用法差異,以及nil coalescing
(??
)運算符的底層邏輯。
其本質上是一個枚舉類型
enum Optional<T> {case none // 表示空值(nil)case some(T) // 表示有值,關聯值為具體數據
}
使用?聲明一個可選類型,表示該變量肯為nil
!強制解包,將可選類型強制轉換為非可選類型
if let 安全解包方式,判斷可選值是否為nil,若有值,將值綁定到新變量并執行代碼塊,若為nil則跳過代碼塊
guard let 可選綁定-提前退出
??用于為可選值提供默認值
Objective-C 中strong
、weak
、assign
、copy
四種屬性修飾符的區別是什么?
修飾符 | 內存管理策略 | 適用場景 | 核心特點 |
---|---|---|---|
strong | 強引用,會增加對象的引用計數(retain ),持有對象直至自身被釋放。 | 大多數對象類型(如自定義類實例) | 確保對象不會被意外釋放,是默認的對象修飾符。 |
weak | 弱引用,不增加引用計數,當對象被釋放后,指針會自動置為?nil (避免野指針)。 | 避免循環引用的場景(如代理?delegate ) | 不持有對象,對象銷毀后自動清空指針,防止訪問已釋放內存導致崩潰。 |
assign | 直接賦值,不涉及引用計數,適用于基本數據類型。 | 非對象類型(如?int 、float 、CGFloat ?等) | 用于基本數據類型,若用于對象類型,對象釋放后指針不會清空,可能導致野指針。 |
copy | 創建對象的副本并持有副本(copy ?操作),不關心原對象的生命周期。 | 不可變對象(如?NSString 、NSArray ?等) | 確保屬性持有獨立的副本,避免受原對象修改的影響。 |
Swift 中的inout
參數和 Objective-C 的指針參數有什么異同
兩者的核心目的一致:允許函數修改外部傳入的變量,打破了函數參數默認的 "值傳遞" 限制。
Objective-C 指針參數:通過傳遞變量的內存地址(指針),函數可直接修改指針指向的內存數據。
Swift?inout
?參數:通過特殊的傳遞機制,使函數能夠修改外部變量的值。基于 "復制 - 修改 - 寫回"(Copy-In-Copy-Out)機制,并非直接操作內存地址
Objective-C 的@dynamic
和 Swift 的dynamic
關鍵字作用有何不同?(考察對動態特性的理解)
oc中的@dynamic與synthesize均用于處理屬性的存取方法,但是行為完全相反
synthesize為默認行為,告訴編譯器自動生成屬性的存取方法,如果未顯示聲明,那么編譯器會默認為屬性生成synthesize property = _property
@dynamic告訴編譯器不要自動生成存取方法和實例變量,由開發者來提供
在swift中
KVO(鍵值觀察):Swift 的屬性默認不支持 KVO,標記?dynamic
?后才能被觀察
隱含?@objc
?的效果(自動暴露給 Runtime),且強制開啟動態分發,確保成員能被 Runtime 動態修改(如方法交換)。
Swift 的Extension
能否添加存儲屬性?如果不能,如何實現類似 “添加存儲屬性” 的效果?**(考察對 Swift 類型系統的理解)
擴展是不改變原有類型結構的前提下為其添加功能
擴展的核心作用是 “擴展功能” 而非 “修改結構
通過 Objective-C Runtime 的關聯對象機制,為類(Class)添加 “偽存儲屬性”
?Objective-C 中NSObject
的isKindOfClass:
和isMemberOfClass:
有什么區別?在 Swift 中如何實現類似判斷?(考察對類繼承與元類的理解)
在 Objective-C 中,一切對象(包括類本身)都是?NSObject
?的實例,存在兩條關鍵的繼承鏈
實例對象的繼承鏈:實例對象 → 類對象(如?[Person class]
)→ 父類對象(如?[NSObject class]
)→?nil
。
類對象繼承鏈:類對象 → 元類對象(Meta Class,類的 “類”)→ 父元類對象 → 根元類(Root Meta Class)→ 根類(NSObject
)→?nil
。
調用?[obj isKindOfClass:cls]
?時,會檢查?obj
?的整個繼承鏈(包括自身所屬類及所有父類)。
調用?[obj isMemberOfClass:cls]
?時,僅檢查?obj
?直接所屬的類(不包含父類)。
Swift 中protocol
的mutating
關鍵字有什么作用?
mutating
?關鍵字用于修飾協議中的方法,表明該方法?允許修改遵循協議的結構體(struct
)或枚舉(enum
)的實例本身。