引言:为什么性能从第一天起就很重要
当你开始用Swift编写代码时,很容易只关注功能性:"只要能用就行"。然而,经验丰富的开发者知道:性能优化不是最后的润色,而是从第一行代码就开始打下的基础。慢速的应用会流失用户、消耗电池并收到差评。
在本文中,我们将分析优化iOS和macOS的Swift应用的关键方面。你将了解如何避免新手常见错误,学会处理内存、线程和性能分析。每个部分都包含实用的代码示例,你可以立即应用到自己的项目中。
1. 内存管理:ARC与避免循环引用
Swift使用自动引用计数(ARC)来管理内存。这意味着当对象不再有强引用时,它们会被释放。但如果你创建了循环引用,内存将永远不会被释放——就会发生内存泄漏。
弱引用和无主引用
使用weak和unowned来打破循环。这通常在闭包和委托中需要用到。
class ViewController: UIViewController {
var networkManager: NetworkManager?
func fetchData() {
networkManager?.fetch { [weak self] result in
guard let self = self else { return }
// 处理结果
self.updateUI(with: result)
}
}
}
何时使用:
weak— 如果引用可能变为nil(例如委托)。unowned— 如果你确定对象的生命周期比闭包长(例如父控制器)。
避免不必要的拷贝
值类型(结构体、枚举)在赋值时会被拷贝。对于大数据,使用class或通过inout传递引用。
// 不好:拷贝大数组
func processLargeArray(_ array: [Int]) {
// array — 是副本
}
// 好:通过引用传递
func processLargeArray(_ array: inout [Int]) {
// array — 是对原数组的引用
}
2. 多线程处理:GCD和async/await
iOS和macOS是多线程系统。如果你在主线程上执行繁重操作(数据加载、图像处理),界面会"卡死"。使用Grand Central Dispatch(GCD)或现代的async/await。
GCD:基础模式
DispatchQueue.global(qos: .userInitiated).async {
// 在后台执行繁重工作
let result = performHeavyCalculation()
DispatchQueue.main.async {
// 在主线程更新UI
self.label.text = "\(result)"
}
}
服务质量(QoS):
.userInteractive— 用于UI(几乎即时)。.userInitiated— 用于用户操作(几秒内)。.utility— 用于长时间任务(进度条)。.background— 用于后台同步(不紧急)。
Async/await(Swift 5.5+)
更易读的异步处理方式:
func fetchImage(from url: URL) async throws -> UIImage {
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else {
throw URLError(.badServerResponse)
}
return image
}
// 在Task中调用
Task {
do {
let image = try await fetchImage(from: url)
self.imageView.image = image
} catch {
print("加载错误:\(er