了解苹果为何创造 Swift、它如何逐步在 iOS 应用中取代 Objective-C,以及这一转变对工具链、招聘与代码库的实际影响。

Swift 并不是苹果“为好玩”造的一个新语言。它是对 iOS 开发中真实痛点的回应:迭代缓慢、容易无意写出的不安全模式,以及随着应用复杂度增长而与 Objective-C 旧设计之间不断扩大的不匹配。
本文回答一个实用问题:为什么 Swift 会出现、它如何成为默认语言,以及这段历史至今如何影响你的代码库和团队决策。
你会得到一条清晰且轻量的时间线——从早期 Swift 版本到稳定且广泛采用的工具链——不被琐事淹没。过程中我们会把历史与日常后果联系起来:开发者如何写更安全的代码、API 如何演化、Xcode 工作流发生了什么变化,以及“现代 Swift”在并发和 SwiftUI 等特性下意味着什么。
Objective-C 在许多成功应用中仍然存在,特别是旧代码库和某些库。本文目标不是制造恐慌或紧迫感,而是澄清:Swift 并没有一夜之间抹去 Objective-C;它是通过互操作性与生态系统的变化逐步接管的。
Objective-C 是苹果开发数十年的基础。当第一版 iPhone SDK 在 2008 年到来时,Objective-C(加上 Cocoa Touch 框架)是构建应用的主要方式,就像在 Mac OS X 上使用 Cocoa 一样。如果你在早期写 iOS 应用,你实际上是通过 Objective-C 学习苹果平台的约定。
Objective-C 有很多优点——尤其当你深入“Cocoa 方式”后。
它基于强大的动态运行时:消息机制、反射、类别(categories)和方法交换(method swizzling)支持灵活且“插件式”的模式。Cocoa 约定(代理、target–action、通知、KVC/KVO)与文档紧密结合,易于使用。
同样重要的是,生态成熟。苹果的框架、第三方库以及多年累积的问答都以 Objective-C 为假定基础。工具链和 API 围绕它建立,团队能以可预测的技能要求招聘开发者。
痛点不是抽象哲学问题,而是日常的摩擦。
Objective-C 在某些场景下相对冗长,尤其是“简单”任务。方法签名、方括号和样板代码让代码更长、扫描起来更难。一些 API 暴露了大量指针概念,在 ARC(自动引用计数)普及之前尤其容易出错。
内存与安全问题长期存在。即便有了 ARC,仍需理解所有权、引用循环以及可空性如何在运行时出乎意料地影响行为。
与 C API 的交互也很常见,但并不总是愉快。桥接 C 类型、处理 Core Foundation、管理“toll-free bridging”增加了心理负担,让代码感觉不像现代应用代码。
遗留 iOS 代码库通常依赖 Objective-C,因为它们稳定、经过考验且难以重写。许多长期存在的应用包含 Objective-C 层或旧依赖项,它们仍然在做真实且可靠的工作。
苹果并不是因为 Objective-C “坏”才造 Swift。Objective-C 支撑了多年的成功 iPhone 与 Mac 应用。但随着应用变大、团队增多、API 扩展,一些 Objective-C 默认行为的成本变得更明显——尤其当把小概率的错误在百万行代码上成倍放大时。
一个主要目标是让常见错误更难以写出。Objective-C 的灵活性很强,但它可能把问题隐藏到运行时:向 nil 发送消息、混淆 id 类型、或在 API 中错误处理可空性。很多问题可以通过纪律、约定和代码审查来缓解——但在大规模下代价仍很高。
Swift 内置了护栏:可选类型(optionals)迫使你思考“这个可能不存在吗?”,强类型减少了误用,guard、switch 的穷尽校验以及更安全的集合处理把更多错误推到编译期而不是生产环境。
Swift 也让写代码的日常体验现代化。简洁的语法、类型推断以及更丰富的标准库让许多任务在比头文件/实现文件模式、冗长的泛型技巧或宏重度使用下更清晰。
在性能方面,Swift 的设计允许激进的编译器优化(尤其在值类型和泛型上)。这并不保证每个 Swift 应用都比每个 Objective-C 应用更快,但它给了苹果一个可以随着时间演进以提高性能的语言模型,而不必过度依赖动态运行时行为。
苹果需要 iOS 开发对新手更友好,并使长期产品可持续。Swift 的 API 命名约定、调用处更清晰的意图以及对表达性类型的强调,旨在减少“部落知识”,让代码库在数月后更容易读懂。
结果是:更少的脚枪(foot-guns)、更干净的 API,以及一种更适合大团队长期维护的语言——并不是说 Objective-C 做不到这些事。
Swift 并非一鸣惊人地“赢得”了生态。苹果把它作为新代码的更好选择推出,随后用了多年时间使其稳定、更快,并更容易与现有 Objective-C 应用并存。
ABI 稳定意味着 Swift 运行时与标准库在二进制层面上与 Swift 5 的不同版本兼容。在 Swift 5 之前,许多应用必须在包里携带 Swift 库,导致应用体积增加并复杂化分发。ABI 稳定后,Swift 在与 Objective-C 相似的方式上变得更加可靠,编译后的代码可以跨系统更新运行,从而让团队更愿意在长期生产代码中使用 Swift。
多年里,很多团队在为新功能使用 Swift 的同时把核心模块留在 Objective-C。这种逐步路径——而非一次性重写——让 Swift 的崛起对真实应用与真实截止日期来说更具可行性。
Swift 并不是通过强制所有团队丢弃有效的 Objective-C 代码获胜的。苹果确保两种语言能在同一个应用目标中共存。这种兼容性是 Swift 采纳不在第一天就停滞的重要原因。
混合代码库在 iOS 中很常见:你可能把旧的网络层、分析或 UI 组件留在 Objective-C,而用 Swift 编写新功能。Xcode 直接支持这种方式,因此“Swift 取代 Objective-C”通常意味着渐进改变,而不是一次性大规模重写。
互操作通过两种互补机制实现:
YourModuleName-Swift.h)来暴露与 Objective-C 兼容的 Swift 类与方法。你通常通过 @objc 属性或继承自 NSObject 来选择性地暴露。你不需要记住所有细节才能受益,但理解“要把某些类型暴露给另一种语言需要显式步骤”能解释为什么某些类型自动可见,而另一些则不可见。
大多数团队会遇到一些反复出现的集成点:
真实的应用是长期存在的。互操作性允许你逐特性迁移、持续交付并降低风险——尤其当第三方 SDK、旧组件或时间限制使得一次性全部转换不现实时。
Swift 不只是现代化语法——它改变了日常 iOS 代码的“常态”。许多以前依赖约定(和严密代码审查)的模式,变成了编译器可以帮助强制执行的事情。
Objective-C 开发者习惯向 nil 发送消息会安静地什么都不做。Swift 用可选类型(String?)把缺失显式化,促使你用 if let、guard 或 ?? 处理。这通常能防止一类崩溃和“为什么这是空的?”的逻辑错误——但并不意味着完全杜绝错误。
Swift 能在很多地方推断类型,减少样板代码的同时保持可读性:
let title = "Settings" // inferred as String
更重要的是,泛型让你在不依赖 id 和运行时检查的情况下编写可重用、类型安全的代码。把“任意元素数组”换成“正好是我期望的类型数组”,能减少意外对象混入和强制转换。
Swift 的 throw/try/catch 鼓励显式的错误路径,而不是忽略失败或传递 NSError **。集合有强类型([User]、[String: Int]),字符串是完整的 Unicode 正确 String,而不是 C 字符串、NSString 与手动编码决策的混合。总体结果是更少的越界错误、更少的无效假设,以及更少“能编译但运行时崩溃”的问题。
Objective-C 的运行时在运行时模式上依然有价值:方法交换、动态消息转发、某些依赖注入方式、基于 KVC/KVO 的代码以及旧的插件式架构。Swift 可以与这些互操作,但当你确实需要运行时动态性时,Objective-C 仍然是一个实用工具。
Swift 不只是改变语法——它推动 iOS 生态去现代化工具链与约定。这一转变并非总是顺利:早期 Swift 版本常带来更慢的构建、卡顿的自动补全以及看似风险更高的重构。随着时间推进,开发体验成为 Swift 的重要优势之一。
Xcode 对 Swift 的支持在日常细节上变得更好:
如果你在 Swift 1.x/2.x 时代使用过它,可能记得很多不顺;从那以后趋势是持续改进:更好的索引、更稳定的源码支持,以及更少的“Xcode 异常”时刻。
Swift Package Manager(SPM)在很多团队减少了对外部依赖系统的需求。基本上,你声明包与版本,Xcode 解析并集成它们,构建无需额外的项目文件操作。它并非适合所有场景,但对许多应用来说简化了入门并让依赖更新更可预测。
苹果的 API 设计指南推动框架向更清晰命名、更好的默认行为与能传达意图的类型靠拢。这种影响蔓延到第三方库,更多库采用 Swift 优先的 API,使现代 iOS 代码库更一致——即便其底层仍可能桥接到 Objective-C。
UIKit 仍然存在。大多数生产级 iOS 应用仍然大量依赖它,尤其在复杂导航、细腻手势、高级文本处理以及经过长期打磨的 UI 组件上。变化在于:现在书写 UIKit 代码的默认语言通常是 Swift——即便底层框架相同。
对许多团队来说,“UIKit 应用”不再等同于 Objective-C。Storyboard、nib 和代码视图常由 Swift 视图控制器与 Swift 模型驱动。
这种转变重要因为苹果越来越多地以 Swift 可用性为中心设计新的 API(更清晰命名、optionals、泛型、result 类型)。即使这些 API 也对 Objective-C 可用,Swift 的覆盖层往往更像“首选”表面,这会影响新开发者在 UIKit 代码库中的上手速度。
SwiftUI 不只是绘按钮的新方式。它推动了一种不同的心智模型:
在实践中,这改变了应用架构讨论。采用 SwiftUI 的团队通常更强调单向数据流、更小的视图组件,以及把副作用(网络、持久化)从视图代码中隔离开来。即便不全面采用,SwiftUI 在表单、列表和以状态驱动布局的屏幕上能减少大量样板代码。
发布应用时经常会混合使用两者:
UIHostingController 在 UIKit 中嵌入 SwiftUI 新界面。这种混合方法让团队保留成熟的 UIKit 基础设施(导航栈、协调器、现有设计系统),同时在明显受益的地方渐进采用 SwiftUI,将风险控制在可接受范围内。
如果你现在开始启动新项目,苹果最新的 UI 故事是 SwiftUI,很多相关技术(Widget、Live Activities、某些扩展)也强烈偏向 Swift。即便在 UI 之外,Swift 友好的 API 趋势也在塑造默认:新项目通常以 Swift 为准,决策更多是“我们需要多少 UIKit?”而不是“是否使用 Objective-C?”
结果不是某个框架替代另一个,而是 Swift 成为连接旧路径(UIKit)与新路径(SwiftUI)的共同语言。
并发是指应用如何在“同时做多件事”时(如加载数据、解码 JSON、更新界面)不阻塞界面。Swift 的现代方案旨在让这些工作看起来更像正常代码,而不是线程杂耍。
借助 async/await,你可以像自上而下的顺序那样编写异步工作(如网络请求):
async 标记一个可能会挂起的函数。await 是“在这里暂停,直到结果就绪”的点。不再是深度嵌套的回调,你可以像读菜谱一样读代码:先获取数据、解析,然后更新状态。
Swift 把 async/await 和 结构化并发 结合起来,基本含义是:“后台工作应该有明确的拥有者和生命周期。”任务在某个作用域中创建,子任务与父任务绑定。
这意味着:
两个概念有助于减少并发访问引发的随机崩溃:
大多数团队不会一夜之间全部切换。常见的做法是在现代 Swift 并发与旧模式(OperationQueue、GCD、委托回调和完成处理器)之间混合使用,尤其在需要集成旧库或旧的 UIKit 流程时。
把一个真实的 iOS 应用迁移并非“把一切都转掉”的项目——它是一个风险管理项目。目标是在持续交付的同时逐步减少需要维护的 Objective-C 代码量。
常见方法是增量迁移:
这让你在保持交付的同时逐步建立信心并控制影响范围,尤其在有死线时不会让迁移阻塞发布。
若干 Objective-C 模式难以直接转译:
objc_runtime 的代码常常需要重设计。把迁移当成一次实现替换,而不是功能变更。先为关键流程(网络、缓存、支付、鉴权)添加表征测试,然后再迁移。快照测试(snapshot tests)能在 UI 从 UIKit 转到 Swift 时帮助捕获回归。
为团队制定轻量标准:编码约定、lint(如 SwiftLint)、模块边界、bridging header 规则,以及“除非有正当理由不新增 Objective-C”。把流程写出来可以防止代码库以不一致的方式变成双语混合。
Swift 不只是改变语法——它改变了 iOS 团队的“常态”。即便你的产品里仍有 Objective-C,日常在人事、流程与长期维护上的决策已经被以 Swift 为先的期望所影响。
大多数新的 iOS 职位默认假设会使用 Swift。候选人可能从未在职业生涯中交付过 Objective-C,这会影响在混合代码库中的磨合时间。
实际建议:把 Objective-C 技能当作“加分项”,而不是门槛,并准备好入职材料,明确指出代码库中 Objective-C 存在的位置与原因。一份关于 bridging header、文件归属与“无上下文请勿触碰”区域的简短内部指南能防止新人犯错。
Swift 的更强类型与显式可选能让审查更快:审查者花更少时间猜测值的可能性,而把精力放在校验意图上。协议、泛型与值类型等模式也鼓励更一致的架构——前提是被谨慎使用。
另一方面是风格漂移。团队应采用统一的 Swift 风格指南并使用自动格式化/lint 工具,使审查聚焦行为而非空白与风格细节。(如果已有指南,把它们链接到内部文档中心。)
当你能直接使用现代 API,而不是维护围绕旧模式的自定义封装时,维护会更容易。但 Objective-C 不会在一夜之间消失——尤其是在包含成熟、经过市场检验模块的应用中。
对混合代码库要有现实预算:把迁移规划与业务里程碑结合,而不是把它当作无尽的“清理”任务。定义什么叫“完成”(例如:所有新代码用 Swift,旧模块仅在必要时改动),并在大规模重构时重新评估该规则。
有关决策框架,请参见 /blog/migrating-objective-c-to-swift。
在 Swift 与 Objective-C 之间做选择通常不是哲学问题,而是成本、风险与时间线的问题。好消息是,你很少需要选择“全有或全无”。大多数团队通过在原地演化代码库能获得最佳结果。
如果是新项目,Swift 应作为默认语言。它与苹果最新 API 保持一致,具备更好的安全特性,并能直接使用现代模式如 async/await。
首要决策是 UI 策略:UIKit(用 Swift)、SwiftUI,还是两者混合。如果犹豫不决,可以比较 /blog/swiftui-vs-uikit 中的权衡。
对于已有 Objective-C 的应用,保留稳定、经过测试的模块,并在能快速受益的地方引入 Swift:
实用规则:当你能定义清晰边界(API 表面、归属与测试)时,启动一个新的 Swift 模块。当代码成熟并高度耦合或改动风险大时,保持 Objective-C 稳定。
有关规划,请查看 /blog/ios-migration-checklist。
对个人与团队而言,以下顺序适合日常 iOS 开发:
iOS 现代化常常会显现出与之相邻的工作竞争同一份工程时间:管理后台、内部工具、后端服务与 iOS 应用依赖的 API。如果你希望 iOS 团队在迁移 Swift 的同时还要继续交付配套软件,Koder.ai 可以通过对话驱动的工作流帮助你快速搭建 web 应用、Go 后端(含 PostgreSQL)或 Flutter 伴生应用——并导出源码、部署、使用快照/回滚 管理迭代。
如果你希望外部帮助来评估下一个最安全步骤(新模块、部分迁移或“保持不动”),请参见 /pricing。
Swift 的诞生旨在减少常见的 iOS 开发风险(例如意外的 nil 行为和松散类型),提高大型代码库的可读性与可维护性,并为编译器优化提供更好的语言模型。它并不是在说 Objective-C “有问题”——而是要在规模化开发中让更安全、更现代的默认行为更容易被采用。
Swift 成为默认语言是渐进的结果:
这些因素使得“新功能用 Swift 实现”成为大多数团队最省力的路径。
Swift 5 在 Apple 平台上引入了 ABI 稳定性,意味着编译后的 Swift 代码在二进制层面上可以与系统随带的 Swift 运行时/标准库兼容。在此之前,很多应用需要将 Swift 库一起打包进 App,造成体积和分发复杂度增加。ABI 稳定后,应用体积、部署可靠性和长期维护都有明显改善,让团队更愿意把 Swift 用于生产级代码。
在同一应用 target 中可以混合使用两种语言:
YourModuleName-Swift.h 的头文件,暴露对 Objective-C 兼容的 Swift API,通常需要用到 @objc 或继承自 NSObject。并不是所有 Swift 特性都能被 Objective-C 使用,因此在设计边界时要主动规划哪些类型需要暴露。
可选类型(T?)把“值可能缺失”这一概念显式化,并在编译期强制处理(例如使用 if let、guard、??)。在 Objective-C 中,对 nil 的消息调用会安静地无操作,且可空性有时不明确,这些情况容易导致运行时错误。可选类型的实用效果是减少崩溃与“值竟然为空”的逻辑错误。
Swift 的泛型与强类型系统减少了类型转换与运行时类型检查(Objective-C 中常见的 id 和未类型化集合)。在实践中,你会得到:
[User],而不是“任意元素的数组”;当你确实需要运行时动态性时,Objective-C 依然优越,例如大量使用 KVC/KVO、方法交换(swizzling)、基于 selector 的 API 或某些插件式架构。Swift 能与这些场景互操作,但要在纯 Swift 中重现相同动力学通常需要重设计,而不是直接翻译。
一个务实的迁移策略是增量迁移:
把迁移当成风险管理:在持续交付的同时,逐步降低长期维护成本。
常见陷阱包括:
@objc、继承 NSObject,并受限于可用语言特性;在替换实现之前先规划边界并补充测试,能大幅降低风险。
完全不必二选一。很多生产应用是混合的:
UIHostingController 在 UIKit 中嵌入 SwiftUI 屏幕;这种方式让团队在能显著减少样板代码的地方采用 SwiftUI,同时保留成熟的 UIKit 导航和复杂组件,风险更可控。