当前位置:首页>iOSAPP>你的 iOS App 卡顿?这 12 个 Swift 性能秘密或许能救你

你的 iOS App 卡顿?这 12 个 Swift 性能秘密或许能救你

  • 2026-10-30 17:13:08
你的 iOS App 卡顿?这 12 个 Swift 性能秘密或许能救你

这里每天分享一个 iOS 的新知识,快来关注我吧

前言

有些 Swift 性能优化的细节,苹果文档里其实都有,但很多人可能没仔细看过。

我平时会记录一些我踩过的坑,今天整理一下分享出来,希望能帮你少走弯路。

Copy-on-Write:数组复制的隐藏成本

Swift 的 Array、Dictionary、Set 用了 Copy-on-Write(COW)机制。赋值时不会立刻复制,只有修改时才真正复制。

var arr1 = [1, 2, 3]var arr2 = arr1   // 还没复制,共享内存arr2.append(4)    // 现在才复制

但如果你在循环里频繁修改大数组,还是会触发多次复制。

我之前解析 JSON,1000 条数据花了 2 秒。后来加上 reserveCapacity(1000),直接降到 0.3 秒。

知道数组大概多大时,提前用 reserveCapacity() 预留空间,能避免多次重新分配内存。

值类型 vs 引用类型:性能差很多倍

Swift 优先用值类型(struct、enum),而不是引用类型(class)。

值类型存在栈上,复制快。引用类型在堆上,还要走 ARC,开销大。

struct Point {var x: Doublevar y: Double}// 值类型复制,很快var p1 = Point(x: 1, y: 2)var p2 = p1   // 栈上复制,成本低

在游戏引擎、音频处理这些场景,用 struct 代替 class 能带来明显的性能提升。

除非需要继承或共享可变状态,否则优先用 struct。

ARC 开销可能是看不见的性能杀手

ARC 每次赋值、传参都会触发 retain/release。普通代码里这点开销可以忽略,但在循环里会累积起来。

我之前有个列表页面,滚动时卡顿。用 Instruments 一测,发现是 ARC 开销太大。把数据模型从 class 改成 struct,流畅度立马提升了。

用 struct 代替 class,值类型不走 ARC。闭包里用 [weak self] 避免强引用:

networkRequest { [weak self] data inself?.handle(data)}

函数内联可能让编译器帮你优化

函数调用有开销,编译器会在合适的时候内联函数。

静态分发 vs 动态分发:静态分发是编译器知道调用哪个函数,快。动态分发是运行时才决定,慢。

final class Dog {func bark() { print("Woof!") } // 静态分发}

类不会被继承时加 final,让编译器用静态分发。这个优化在性能关键路径上还是挺有用的。

懒加载:别让高阶函数拖慢你

map、filter、reduce 写起来爽,但可能会创建中间数组。

// 效率低,会创建临时数组let squared = (0..<1000).map { $0 * $0 }.filter { $0 % 2 == 0 }

用 lazy 可以延迟计算,避免创建中间数组。但最直接的方式还是用 for-in 循环。大数据量时用 lazy,性能关键路径用 for-in。

内存对齐:结构体的隐藏陷阱

Swift 会对齐数据,如果结构体里混着大小不同的类型,会插入填充字节,浪费内存。

// 不好的布局,浪费内存struct Bad {var a: Int8// 1 字节var b: Int64// 8 字节var c: Int8// 1 字节// Swift 会在 a 后面插入 7 字节的填充}

这个优化在普通 App 里可能不明显,但在游戏引擎、图形处理这些场景,能带来明显的性能提升。设计性能关键的结构体时,把相同大小的属性放一起。

并发优化可能让异步代码飞起来

Swift Concurrency(async/await、TaskGroup、Actors)让并发编程更安全,但也有开销。任务切换、同步、Actor 隔离,这些都是成本。

Actor 能保护共享状态,但如果太多任务同时访问同一个 Actor,会形成瓶颈。避免"热 Actor",可以分片(sharding)或者批量更新。

编译器优化,让代码跑得更快

Swift 编译器有很多优化选项:Whole Module Optimization (WMO) 跨文件优化,Release 模式默认开启。-Osize 优化二进制体积,-Ofast 激进优化(可能违反 IEEE 数学规则)。

性能测试一定要用 Release 模式,Debug 模式的性能不具参考价值。我之前在 Debug 模式下测性能,结果完全不对,后来才发现问题。

用 Instruments 找出性能瓶颈

优化之前先测量,Instruments 是 iOS 开发者的必备工具。Time Profiler 找出耗 CPU 的函数,Allocations 追踪内存使用和 ARC 开销,Leaks 发现循环引用,Energy Log 找出耗电的代码。

我之前有个 SwiftUI 列表,滚动时卡顿。用 Time Profiler 一测,发现是在主线程解析 JSON。移到后台 Task 里,立马流畅了。这种问题其实挺常见的,但很多人可能没意识到。

优化前后都要测,你永远不知道瓶颈在哪里。

实战场景:JSON 解析、Core Data、SwiftUI

JSON 解析:

let decoder = JSONDecoder()decoder.keyDecodingStrategy = .useDefaultKeys  // 避免字符串转换开销let users = try decoder.decode([User].self, from: data)

大 JSON 考虑用流式解析,别一次性加载全部。

Core Data:

  • 给常用查询字段加索引
  • 只取需要的字段(propertiesToFetch)
  • 用批量更新,别在循环里改
let request = NSFetchRequest<NSDictionary>(entityName: "User")request.resultType = .dictionaryResultTyperequest.propertiesToFetch = ["id", "name"]  // 只取需要的字段

SwiftUI:

  • 避免不必要的重渲染
  • 把大视图拆成小视图
  • 用 @StateObject 代替 @ObservedObject,避免重复创建
struct ContentView: View {@StateObject private var viewModel = UserViewModel()  // 只创建一次var body: some View {UserListView(users: viewModel.users)    }}

最后

掌握这些优化技巧,不只是让代码跑得更快,更是让你成为一个更强的 iOS 开发者。

你遇到过哪些 Swift 性能问题?是怎么解决的?评论区聊聊。

红包封面还未领完,快领

这里每天分享一个 iOS 的新知识,快来关注我吧

最新文章

随机文章