一定要学好 Optional
Swift 的 Optional 不是“语法糖”,而是安全屏障。
变量“可能有值也可能没有”时,编译器强制你显式处理,把空指针崩溃消灭在编译期。
三种常见玩法
| 玩法 | 代码示例 | 场景说明 |
|---|---|---|
| 可选绑定 | if let name = nameLabel.text { } | 安全解包,作用域内 name 为非可选 |
| 空合运算符 | let count = cartCount ?? 0 | 为 nil 时给默认值 |
| 可选链 | let upper = user.profile?.nickname?.uppercased() | 任意环节为 nil 时整条返回 nil |
初学者易踩的坑
// 错误:强制解包 ! 只用于“绝对确定有值”
let price = dict["price"] as! Double // 一旦 key 不存在直接崩溃
// 正确:先判断再转
if let price = dict["price"] as? Double {
print("价格:\(price)")
}
语法差异速览(Swift vs Java / C++ / Python)
| 差异点 | Swift 写法 | 对比说明 |
|---|---|---|
| 句末分号 | 可省 | C/Java 必须写;Swift 只在同一行多条语句时需要 |
| 类型推断 | let x = 5 | Java 必须 int x = 5; |
| 枚举带值 | enum Barcode{ case qr(String) } | Java 枚举无法直接存关联值 |
| 错误处理 | do-try-catch | Java checked exception 必须声明 throws |
| 字符串插值 | "你好,\(name)" | C++ 需要 stringstream 或 printf |
| 区间匹配 | case 1..<5: | Python/Java 无原生区间模式匹配 |
数据类型怎么选?
| 类型 | 典型场景 | 内存/精度提示 |
|---|---|---|
| Int | 计数、索引 | 64 位,与现代 CPU 寄存器宽度一致 |
| Double | 金融、地理坐标 | 优先用 Double,Float 仅在大量 3D 顶点且 GPU 限制时使用 |
| String | 用户输入、JSON | 值类型,拷贝时采用写时优化(COW, Copy-On-Write) |
| Array | 有序列表 | 值语义,多线程环境下无需额外加锁 |
| Set | 去重、交集运算 | 元素需满足 Hashable 协议以保证哈希值正确 |
| Enum | 有限状态 | 关联值可携带 payload(有效载荷),替代继承更轻量 |
自定义类型示例
enum UserRole: String {
case admin, editor, viewer
}
struct User {
let id: Int
var role: UserRole // 比裸 String 安全、可维护
}
// 使用
let me = User(id: 1, role: .admin)
控制流 & 性能小贴士
-
避免“金字塔”式嵌套:
把多重条件合并,或使用
guard let提前返回。 -
循环里别直接改集合:
用高阶函数
filter/map/reduce,可读且易并行。 -
switch exhaustive 检查:
对 enum 切换时,default 分支能省但未来新增 case 会漏,建议不开 default,让编译器提醒你把所有 case 写完。
函数与闭包:从“会写”到“写好”
函数是第一等公民
func makeAdder(offset: Int) -> (Int) -> Int {
// 返回一个闭包
return { $0 + offset }
}
let add5 = makeAdder(offset: 5)
print(add5(10)) // 15
闭包捕获列表防内存泄漏
class Demo {
var value = 0
lazy var closure: () -> Int = { [weak self] in
// 不加 [weak self] 可能循环引用
return (self?.value ?? 0) + 1
}
}
错误处理:别只用 print(error)
- 自定义错误类型
enum APIError: Error {
case invalidURL
case statusCode(Int)
}
- 异步错误一并处理
do {
let data = try await fetchUser()
} catch APIError.invalidURL {
// 具体错误具体提示
}
工程篇:Xcode、MVVM、调试与真机
MVVM 骨架(伪代码)
// Model
struct Article: Codable { ... }
// ViewModel
final class ArticleListVM: ObservableObject {
@Published private(set) var articles: [Article] = []
func load() async {
articles = await API.getArticles()
}
}
// View (SwiftUI)
struct ArticleListView: View {
@StateObject var vm = ArticleListVM()
var body: some View {
List(vm.articles) { ... }
.task { await vm.load() }
}
}
调试三板斧
- 条件断点:右键断点 → Condition 填入
index == 5 - LLDB 实时改值:
expr luckyNumber = 88 - Thread Sanitizer:Product → Scheme → Diagnostics → 勾选 “Thread Sanitizer”,神仙打架的并发 bug 现形。
真机必做清单
- Apple ID 加入 Xcode Preferences
- Bundle Identifier 与描述文件匹配
- 打开 “Developer Mode” 在 iPhone 设置 → 隐私与安全
- 用 Network Link Conditioner 模拟弱网,提前发现超时/重试逻辑缺陷。
总结
- Optional 与类型安全是 Swift 的“护城河”,越早养成“不强制解包”习惯,越少凌晨修 Crash。
- 值类型(struct/enum)在移动设备上比引用类型更省内存,且线程安全天然优势。
- 高阶函数 + 链式调用能让集合操作像 SQL 一样声明式,可读性提升 > 50%。
- 错误处理要“具体化”,
do-try-catch配合自定义错误类型,调试日志一目了然。 - 调试时先想“如何重现”,再用工具验证假设;乱打断点等于大海捞针。
- 模拟器只解决 70% 问题,真机 + 弱网 + 低电量才是用户真实环境。
Swift 还能做什么?
| 场景 | 技术点 | 一句话提示 |
|---|---|---|
| 服务端(Vapor) | Swift Concurrency | 同一门语言写全栈,模型复用 |
| 数据科学 | Swift for TensorFlow | 利用 value semantic 加速自动微分 |
| 嵌入式/物联网 | Swift on ARM Linux | 内存安全驱动硬件,减少 C 指针隐患 |
| 跨端逻辑共享 | Swift + Kotlin Multiplatform | 把业务模型编译成 .framework 给 Android 调用 |
| 机器学习本地推理 | Core ML + Swift | 模型量化后跑在 Neural Engine,比 GPU 省电 |