聊聊我在杭州从零手敲Swift入门的那些日子
戴着降噪耳机,网易云音乐里正循环着周杰伦的《暗号》,手边的龙井茶刚泡开第二泡。坐标杭州,最近这大环境,虽然都说互联网寒冬,但阿里和网易这边的机会其实一直暗流涌动。为了以防万一,也为了带带团队里刚招来的几个校招生,我决定把之前零碎记录的 Swift 学习笔记整理一下。
说实话,作为一个在代码堆里滚了多年的老兵,我骨子里是个绝对的保守派。我坚持手写代码,总觉得那些靠 AI 一键生成的代码没有灵魂,更别提去深究底层的内存分配和指针走向了。但现实往往很骨感,上周五晚上加班时,产品经理又跑来提了个“简单”的需求,看着那密密麻麻的排期,我不得不向现实低头,开始尝试一些 AI 辅助开发。今天这篇文章,就结合我最近用 AI 工具踩坑和死磕底层原理的经历,给大家盘一盘 Swift 的基础知识。
从 OC 到 Swift 的阵痛与契机
去年双11期间,团队接了个新业务,领导拍板要求全栈使用 Swift 重构。当时我内心是拒绝的,毕竟 Objective-C 用得好好的,那些黑魔法和 Runtime 的骚操作闭着眼睛都能写。但没办法,打工人嘛,领导指哪打哪。
刚切到 Swift 的时候,真的是浑身难受。没有宏定义,没有 #pragma mark,连个 nil 都不能随便乱传。但当你熬过最初的阵痛期,理解了它的设计哲学后,就会发现这玩意儿在安全性上确实降维打击了 OC。
Optional:不只是个带问号的语法糖
新手学 Swift,第一个拦路虎绝对是 Optional(可选型)。无数人在这里被 Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value 这个报错教做人。测试跑过来跟你说“哥,这个页面偶现Crash”,我一听偶现,再一看堆栈是解包失败,血压直接就上来了。
很多人以为 Optional 只是个语法糖,但如果你喜欢研究底层原理,打开 SIL(Swift Intermediate Language)看看就会发现,它本质上是一个带关联值的枚举(Enum)。
// 你写的代码
var name: String? = "杭州"
// 编译器眼里的代码
enum Optional<Wrapped> {
case none
case some(Wrapped)
}
当你使用 ! 强制解包时,其实是在做一个模式匹配。如果底层是 .none,就会直接触发 fatalError()。所以,作为保守派,我强烈建议新手戒掉 !,多用 if let 或者 guard let。
// 优雅的处理方式
guard let userName = name else {
print("名字为空,直接提前返回")
return
}
print("你好, \(userName)")
值类型 vs 引用类型:性能优化的底层逻辑
在 iOS 开发中,性能优化永远是个绕不开的话题。Swift 提供了 Struct(值类型)和 Class(引用类型)。很多从 Java 或 OC 转过来的人,习惯性地全用 Class,这其实浪费了 Swift 的一大杀器。
这里我整理了一个对比表格,大家可以直观感受一下:
| 特性 | Struct (值类型) | Class (引用类型) |
|---|---|---|
| 内存分配 | 栈区(小对象)/ 堆区(大对象) | 堆区 |
| 赋值操作 | 深拷贝(Copy-on-Write 优化) | 浅拷贝(引用计数 +1) |
| 底层派发 | 静态派发(直接寻址,极快) | 动态派发(V-Table / W-Table) |
| 继承 | 不支持 | 支持 |
| 引用计数 | 无 | 有(ARC 管理) |
看到没?Struct 的赋值是拷贝,而且方法调用是静态派发。这意味着在 CPU 缓存命中率上,Struct 完爆 Class。在写一些高频调用的数据模型(比如 TableView 的 Cell 配置数据)时,我全部换成了 Struct, Instruments 跑出来的帧率确实稳了不少。
闭包与 ARC:那些让人头秃的循环引用
说到内存管理,就不得不提闭包(Closure)和 ARC(自动引用计数)。OC 时代的 __weak 和 __strong 舞蹈,在 Swift 里变成了 [weak self] 和 [unowned self]。
这里有个坑我踩了好几次。有一次写个网络请求的回调,顺手写了个 [unowned self],结果页面还没加载完用户就退出了,网络回调触发时直接 Crash。
为什么?因为 unowned 是非拥有关系,但它假设对象一定存在。如果对象被释放了,你再访问它,就会访问到野指针。而 weak 在对象释放后会自动变成 nil。
// 安全的闭包写法
networkManager.fetchData { [weak self] result in
guard let self = self else { return }
self.updateUI(with: result)
}
这里顺便提一嘴底层原理。ARC 并不是垃圾回收(GC),它是在编译期插入 objc_retain 和 objc_release 调用。Swift 为了优化性能,引入了 SIL 层面的 ARC 优化,能自动消除很多多余的引用计数操作。这也是为什么 Swift 跑起来比 OC 感觉更轻快的原因之一。
移动开发实战:适配与审核的血泪史
基础语法搞定后,真正上手写 App 才是噩梦的开始。移动端开发,适配和审核是两座大山。
先说适配。现在 iPhone 的屏幕尺寸简直是个盲盒,从 SE 的小屏到 Pro Max 的大屏,还有刘海屏、灵动岛。以前用 frame 算坐标算到头秃,现在必须拥抱 AutoLayout 和 SwiftUI。特别是 SafeArea 的处理,如果你不处理好底部的小黑条(Home Indicator),你的按钮就会被挡住,测试绝对会给你提个 P0 级的 Bug。
再说 App Store 审核。这绝对是每个 iOS 开发者的痛。上个月我们发版,直接被拒了,理由是 4.0 条款(Design - .Minimum Functionality)。审核员原话是:“App 的 UI 过于简陋,缺乏足够的用户价值。”
当时真的想砸电脑。我们明明是个效率工具,非要逼着我们搞花里胡哨的动画。后来没办法,我让 UI 小姐姐加了几个微交互,又用 DALL-E 生成了一些高质量的占位图和引导页插画(本来想自己画的,但实在没时间,AI 生成的图稍微调一下色调,效果居然出奇的好,审核员看了都挑不出毛病)。重新提交后,秒过。
保守派的 AI 辅助开发反思
回到我开头提到的人设。作为一个坚持手写代码的保守派,我一开始对 AI 辅助工具是极其排斥的。我觉得代码是程序员的艺术品,让 AI 写就像吃预制菜。
但最近项目 deadline 压得太紧,我被迫试用了 CodeBuddy 这个工具。说实话,体验下来有点“真香”了。
比如写一些正则表达式匹配,或者写一套繁琐的 JSON 解析模型(Codable),CodeBuddy 给出的代码不仅准确,而且连注释都写得明明白白。它甚至能根据我的上下文,自动补全一些测试用例。
但是!这并不意味着我们可以当甩手掌柜。AI 生成的代码,你如果不理解它的底层逻辑,出了 Bug 你根本不知道怎么改。
举个例子,有次 CodeBuddy 给我生成了一段处理并发请求的代码,用了 async/await。但它没有考虑到如果其中一个 Task 抛出异常,整个 TaskGroup 会直接取消。如果我不懂 Swift 并发模型底层的结构化并发原理,直接把这个代码合进去,线上绝对会出大事故。
所以,我的结论是:AI 工具(像 CodeBuddy)是极好的“键盘加速器”,它能帮你干掉那些毫无营养的 CRUD 和样板代码,让你有更多时间去思考架构、去抠底层性能、去和 PM 斗智斗勇。但代码的灵魂和最终的兜底责任,依然在你这个“碳基生物”手里。
总结
从 OC 到 Swift,从纯手写代码到尝试 AI 辅助,这一路走来,踩了无数坑,也掉了不少头发。Swift 是一门非常优雅且强大的语言,它的类型安全、面向协议编程(POP)以及底层的性能优化,都值得我们去深入挖掘。
对于想入门 iOS 开发或者正在转 Swift 的同学,我的建议是:多敲代码,多问为什么。不要只停留在“能跑就行”的层面,去翻翻源码,去看看 SIL,去理解内存是怎么分配的。同时,也不要排斥新工具,合理利用 AI 辅助,把精力留给更有价值的思考。
好了,茶喝完了,歌也听完了。产品经理又在工作群里 @ 我了,说那个按钮的圆角还要再调小 1 个像素。不说了,我去改代码了,希望这次提测能一把过,阿门。

评论 0