OC母语的Developer对Swift常见问题的整理
·
1. 基础语法:可选类型(Optional)
题目: 什么是 Optional?为什么需要 Optional?如何安全解包?
答案:
- 定义:Optional 是 Swift 特有的类型,用于表示 “值可能存在(非 nil)或不存在(nil)”,语法上通过?声明(如
var name: String?)。 - 必要性:解决 Objective-C 中 “空指针异常(nil 调用方法崩溃)” 问题,强制开发者显式处理 “值可能为空” 的场景,编译期避免潜在崩溃。
- 安全解包方式:
- 可选绑定(Optional Binding):
if let unwrappedName = name { ... } 或 guard let unwrappedName = name else { return }(推荐,提前退出); - 强制解包(!):
let unwrappedName = name!(危险,nil 时崩溃,仅确定非空时使用); - 隐式解包可选类型(Implicitly Unwrapped Optional):
var name: String!(声明时假定非空,适合初始化后必赋值的场景,如 IBOutlet); - 空合运算符(Nil-Coalescing):
let unwrappedName = name ?? "default"(nil 时使用默认值)。
- 可选绑定(Optional Binding):
2. 数据类型:Struct 与 Class 的区别
题目: Swift 中 Struct 和 Class 有哪些核心区别?分别适用于什么场景?
答案:
Struct:用于存储简单数据(如模型、坐标CGPoint)、强调值相等的场景(如Int、String本质是结构体);
Class:用于需要继承、共享状态(如视图控制器UIViewController)、复杂逻辑的场景。
| 维度 | Struct(结构体) | Class(类) |
|---|---|---|
| 类型性质 | 值类型(Value Type) | 引用类型(Reference Type) |
| 内存存储 | 栈上分配(或嵌入宿主内存) | 堆上分配 |
| 赋值 / 传递行为 | 复制值(深拷贝) | 复制引用(浅拷贝) |
| 继承 | 不支持继承 | 支持单继承 |
| 析构函数 | 不支持 deinit | 支持 deinit(析构) |
| 身份标识(===) | 无(值相等用==) | 有(引用相等用===) |
3. 闭包(Closure):循环引用与捕获列表
题目: Swift 闭包中为什么会产生循环引用?如何解决?请举例说明。
答案:
- 循环引用原因:闭包会默认强引用其捕获的外部变量 / 常量。若闭包被一个对象(如self)强引用,且闭包内部又强引用该对象(如self),则形成 “对象→闭包→对象” 的强引用循环,导致两者都无法释放。
- 解决方式:通过捕获列表(Capture List) 显式声明对捕获变量的引用方式(weak或unowned):
- weak:弱引用,捕获的对象可能为 nil(需用可选类型),适用于对象生命周期可能短于闭包的场景;
- unowned:无主引用,捕获的对象一定非 nil(无需可选类型),适用于对象生命周期与闭包一致的场景(如闭包作为对象的属性,且对象不提前释放)。
class Person {
var name: String
var closure: (() -> Void)?
init(name: String) {
self.name = name
}
deinit {
print("Person deinit")
}
}
// 错误示例:循环引用(self → closure → self)
let person = Person(name: "Alice")
person.closure = {
print(person.name) // 闭包强引用person
}
// 正确示例1:weak(person可能为nil,需解包)
person.closure = { [weak self] in
guard let self = self else { return } // 安全解包
print(self.name)
}
// 正确示例2:unowned(确定person不会提前释放)
person.closure = { [unowned self] in
print(self.name) // 无需解包,若self为nil会崩溃
}
4. 内存管理:ARC 与引用类型
题目: Swift 的 ARC(自动引用计数)如何工作?与 Objective-C 的 ARC 有何异同?
答案:
- ARC 工作原理:ARC 通过跟踪对象的 “强引用” 数量管理内存:
当对象被强引用时,引用计数 + 1;
强引用解除时,引用计数 - 1;
引用计数为 0 时,对象被销毁,释放内存。 - 与 Objective-C ARC 的异同:
- 相同点:核心机制一致(强引用计数管理),都需手动处理循环引用(weak/unowned)。
- 不同点:
Swift 中weak变量必须是可选类型(var obj: Type?),而 Objective-C 中__weak变量可直接声明;
Swift 引入unowned(对应 Objective-C 的__unsafe_unretained),但更安全(编译期检查非空场景);
Swift 的值类型(Struct/Enum)不适用 ARC(栈上分配,无需引用计数),而 Objective-C 几乎全是引用类型。
5. 高级特性:泛型(Generics)
题目: 什么是泛型?请举例说明泛型在 Swift 中的应用场景和优势。
答案:
- 定义:泛型是一种 “类型抽象” 机制,允许函数、结构体、类、协议在不指定具体类型的情况下定义,支持多种类型复用同一套逻辑。
- 应用场景:
通用数据结构(如数组Array、字典Dictionary<K, V>);
通用算法(如交换两个值、排序);
协议关联类型(如Collection协议的Element)。 - 优势:
代码复用:一套逻辑支持多种类型,减少重复代码;
类型安全:编译期检查类型匹配,避免运行时错误;
灵活性:不限制具体类型,同时保证类型约束。 - 示例:实现一个通用的 “交换两个值” 的函数:
// 泛型函数:T为类型占位符,支持任意类型
func swap<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
// 应用于Int
var x = 10, y = 20
swap(&x, &y) // x=20, y=10
// 应用于String
var s1 = "hello", s2 = "world"
swap(&s1, &s2) // s1="world", s2="hello"
6. 异步编程:async/await(Swift 5.5+)
题目: Swift 的 async/await 解决了什么问题?与传统的闭包回调相比有何优势?
答案:
- 解决的问题:传统闭包回调实现异步逻辑时,容易产生 “回调地狱(Callback Hell)”(多层嵌套导致代码可读性差、错误处理复杂)。async/await 用同步的代码风格编写异步逻辑,扁平化代码结构。
- 优势:
代码线性化:避免嵌套,逻辑清晰;
错误处理简单:可通过try/catch统一处理,替代闭包中的错误回调;
可组合性:支持async let并发执行多个异步任务。 - 示例:异步获取用户信息并打印:
// 异步函数:获取用户ID(模拟网络请求)
func fetchUserID() async -> Int {
try? await Task.sleep(nanoseconds: 1_000_000_000) // 模拟1秒延迟
return 1001
}
// 异步函数:通过ID获取用户名
func fetchUserName(for id: Int) async -> String {
try? await Task.sleep(nanoseconds: 1_000_000_000)
return "User_\(id)"
}
// 主逻辑:用async/await调用
func printUserName() async {
let userId = await fetchUserID() // 等待第一个异步任务
let userName = await fetchUserName(for: userId) // 等待第二个异步任务
print("用户名:\(userName)")
}
// 启动异步任务(需在Task中)
Task {
await printUserName() // 输出:用户名:User_1001
}
7. 与 Objective-C 混编
题目: Swift 中如何调用 Objective-C 代码?Objective-C 如何调用 Swift 代码?需要注意哪些问题?
答案:
- Swift 调用 Objective-C:
创建桥接头文件(ProjectName-Bridging-Header.h);
在桥接头文件中导入需要调用的 Objective-C 头文件(如#import “OCClass.h”);
Swift 中直接使用 Objective-C 类(如let obj = OCClass())。 - Objective-C 调用 Swift:
确保Build Settings中Defines Module设为YES;
Swift 类 / 方法需用@objc修饰(暴露给 Objective-C);
Objective-C 中导入自动生成的头文件(#import “ProjectName-Swift.h”),直接使用 Swift 类。
注意事项:
Swift 特有类型(如Optional、Struct、Enum)在 Objective-C 中可能无法直接使用(需用@objc适配);
闭包在 Objective-C 中会转为block,需用@escaping标记逃逸闭包;
协议需用@objc修饰才能被 Objective-C 遵循。
更多推荐


所有评论(0)