2015年那会儿,我刚毕业没多久,揣着一台8G内存的MacBook Air和一本《Objective-C编程之道》,稀里糊涂地进了iOS开发的坑。当时iOS 9刚发布,iPhone 6s还在热卖,3D Touch是全场焦点,Xcode的版本号还停留在7。谁能想到,这一写就是十年。十年里,我从小厂实习生做到大厂技术专家,从一个人扛整个App的开发到带十几人的客户端团队,期间眼睁睁看着Objective-C被Swift按在地上摩擦,看着RN和Flutter冲进来跟原生抢饭碗,看着小程序把一大批独立App变成手机里的僵尸图标,又看着鸿蒙从无到有一步步长成第三个生态。这篇文章不聊虚的,就是把我这十年的技术路径、踩坑经历、选型思路和职业判断原原本本摊开来讲。如果你是刚入行的iOS新人,或者正处于技术转型期纠结要不要做跨平台,又或者单纯想看看一个普通iOS开发者怎么在行业巨变里活下来,那这文值得你花十分钟读完。
1. 站在2015年的起点:那个还是OC的时代
1.1 当时的iOS生态与我的入行契机
2015年的iOS开发圈,和现在完全是两个物种。那会儿Swift 2.0刚在WWDC上亮相,语法稳定性一塌糊涂,几乎没有商业项目敢把Swift放进生产环境。主流语言依然是Objective-C,XIB和Storyboard还是界面开发的主战场,Masonry这种纯代码自动布局框架火得不行,因为大家实在受够了Storyboard拖约束时的卡顿和合并冲突。
我当时所在的创业公司要做一款社交类App,iOS端就我和一个后端两个人。我到现在还记得第一次用Xcode 7连着iPhone 6真机调试时的兴奋感——那个蓝色加载条转完,自己的代码出现在手机屏幕上,那种成就感是同级别的后端同学体会不到的。也是从那时候起,我养成了一个职业病:拿到任何手机,第一件事是看它的系统版本和屏幕尺寸,脑子里自动过一遍适配方案。
这个阶段的核心技术栈现在看简直寒酸:Objective-C配合ARC做内存管理,AFNetworking做网络层,FMDB存本地数据,SDWebImage管图片加载,MJRefresh负责下拉刷新,一套下来基本就是当时所有iOS项目的标准搭配。没有CocoaPods之外更好的依赖管理,没有RxSwift响应式编程的普及,更没有SwiftUI这种声明式UI,大家老老实实地写ViewDidLoad,在代理方法里传值,用KVO监听个属性变化都觉得自己很前卫。
1.2 第一行代码到第一个上架App
我接手的第一个完整需求是做用户注册登录模块,要求支持手机号+验证码的登录方式。现在看这是个再简单不过的需求,但当时我花了整整三天才搞定。因为涉及的东西远不止几个界面那么简单:文本输入框要处理键盘弹起遮挡问题,验证码倒计时要应对前后台切换,登录按钮要有loading状态防止重复点击,token过期了要自动跳转登录页,还要做输入框的二次密码校验。每一环背后都是iOS开发中"看似简单实则坑多"的典型。
记忆最深的是上架审核。我提交了四次才通过:第一次因为没做iPad适配被拒,第二次因为App内出现了"测试"字样被拒,第三次因为隐私权限描述不够明确被拒,第四次才被批准上架。从提交到最终上架花了整整两周,整个过程让我明白了iOS开发和iOS产品是两回事——代码写得再漂亮,过不了审核这关就白搭。这也是我后面几年一直强调"审核前置"思维的原因。
第一次上架成功后,我盯着App Store后台那个空荡荡的下载量统计看了很久。虽然只有零星几十个下载,但那种"世界某个角落里有人正在用我写的软件"的感觉,至今想起来还是很奇妙。也正是这段经历,奠定了一个认知:做客户端开发,技术能力只是基本功,对平台规则的敬畏、对用户体验的在意,才是走得远的关键。
2. 十年技术栈的变迁:从Objective-C到Swift与SwiftUI
2.1 Swift来了,我为什么没有立刻弃OC
Swift发布初期,说实话大多数老iOS开发者是抗拒的。它语法变来变去,Xcode 7时代写好的Swift 1.x代码,升级到Swift 2.x就要改一大片;好不容易升到3.x,4.0又来一次大变动。当时有个段子说"Swift开发者一年学一门新语言",真不是夸张。而且Swift 1.x时代的编译速度慢得吓人,一个中等规模项目的增量编译能等上半分钟,相比OC的编译速度简直是灾难。
我当时对Swift的态度是"接触但不上生产"。个人学习一直在跟进,新开的个人项目尝试用Swift写,但公司核心的电商App始终用OC维护。原因很简单:团队的代码积累、第三方库生态、团队成员技能储备,都决定了迁移成本极高。商业项目不是练手玩具,稳定性永远优先于技术时髦度。
来转折发生在Swift 4.0发布之后。API设计基本定型,ABI在5.0时稳定下来,编译速度大幅优化,我这才在2019年的新项目里全面转向Swift。回头看这个决策节奏,正好踩在了Swift性能稳定的点上,既没有当早期小白鼠,也没有落后太多。对普通开发者来说,新技术采用的最佳时机不是它刚发布的酷炫期,而是它生态成熟后两三个大版本的稳定期。
2.2 架构演进:MVC到MVVM再到Composable Architecture
2015年的iOS架构基本是MVC一统天下。Controller承担了太多的责任,一个正常的页面代码轻松过千行,动辄两三千行的ViewController不是传说而是常态。我拆过最夸张的一个页面Controller,四千多行,里面什么都有——网络请求、数据解析、UI创建、事件响应、动画逻辑、页面统计、埋点上报,活脱脱一个上帝类。
2017年前后,MVVM架构开始流行。起因是ReactiveCocoa和RxSwift把响应式编程的概念带入了iOS圈,ViewModel负责数据加工和业务逻辑,Controller专心做View和ViewModel之间的绑定,代码确实清爽了很多。但当时MVVM也带来了新的烦恼:双向绑定调试起来极其痛苦,一个数据流的追溯要比MVC时代困难好几倍。我一度觉得MVVM是"代码好写了,查Bug变难了"的典型。
到了2020年后,SwiftUI和Combine的出现让声明式UI和单向数据流成为主流,苹果官方推荐的架构也逐渐清晰:View + State + Reducer的结构,本质上借鉴了前端Redux那套理念。我在2022年的新项目里用了类似TCA(The Composable Architecture)的架构,核心感受是:页面状态可预测了,测试好写了,团队协作的边界也清晰了。架构没有银弹,但从整个团队的协作效率和代码可维护性来看,这十年的确是在往更好的方向走。
2.3 一个老项目的Swift重写教训
2020年,我主导了一次把公司核心App从OC迁到Swift的项目,历时七个月,经历堪称教科书级别的反面教材。当时我们决定"大爆炸式重写"——整个App推翻重来,没有采用渐进式迁移方案。结果就是:新App上线后出现了大量回归Bug,用户差评如潮,我们又花了一个多月紧急修复才稳住局面。这次重写的最大教训是:在移动端绝不建议对业务复杂的大型App做"一次性重写"。因为业务逻辑的细节远比你记忆中复杂,很多边界条件是老代码在多年Bug修复中一点点沉淀下来的,重写时根本不可能一次性考虑周全。
更现实的方案是渐进式迁移。核心思路是OC与Swift完全可以共存,即通过桥接文件实现两种语言在同一个工程里互相调用。你可以把新功能模块用Swift写,老模块继续跑OC,利用组件化和路由分层,逐步替换。这样既享受了Swift的现代语法和类型安全,又不至于因为一次性重写导致业务断裂。这个经验后来我几乎在每个技术分享场合都会提,因为踩过的坑实在太大。
另一个重写过程中的大坑是第三方库的Swift适配。2019年之前不少优秀OC库没有Swift版本或维护不及时,迁移时要花大量时间找替代方案或者自己封装。所以如果你现在准备把一个老项目Swift化,第一件事不是写代码,而是先梳理现有第三方依赖的Swift兼容情况,这决定了你迁移方案的时间表。
3. 跨平台混战这五年:RN、Flutter、uniapp与iOS原生
3.1 跨平台方案的选型对比
2017年,React Native异军突起,国内大厂纷纷投入怀抱。2018年底,Flutter 1.0发布,凭借自绘引擎和优秀的渲染性能迅速收割开发者注意力。同时期国内uniapp凭借微信小程序的东风,在一众跨平台框架中成为中小团队的热门选择。到了2025年再看这场战局,原生、React Native、Flutter、uniapp、ArkTS鸿蒙各有各的地盘,普通开发者和技术决策者选型时真的很头疼。
我结合自己的实际项目经验,做个比较主观的横向对比:
| 维度 | iOS原生 | Flutter | React Native | uniapp |
|---|---|---|---|---|
| UI渲染 | 系统原生控件 | 自绘引擎(Skia/Impeller) | JSI原生映射 | WebView+原生混合 |
| 性能 | 最好 | 接近原生 | 中等偏上,复杂场景易卡顿 | 一般,重交互场景吃力 |
| 开发语言 | Swift/OC | Dart | TS/JS | Vue/JS |
| 学习成本 | 高(需熟悉Xcode生态) | 中(Dart较易上手) | 中(前端基础即可) | 低(Vue3语法) |
| 跨端能力 | 仅iOS | Android/iOS/Web/桌面 | Android/iOS/Web | App/小程序/H5 |
| 典型场景 | 高性能要求、深度系统能力 | 中大型App、UI一致性强 | 动态化、团队前端背景 | 中小团队多端快速覆盖 |
我的立场很明确:如果一个产品对UI交互有极致的性能要求,或者需要深度挖掘系统底层能力,原生依然是不可替代的选项。而如果一个初创团队要在最短时间内覆盖App、小程序、H5三端,uniapp的开发效率确实无可匹敌。Flutter和RN则看团队的技术储备:前端基础强的选RN,能接受Dart新语言的选Flutter。
3.2 我用uniapp做微信小程序踩过的坑
2021年,公司决定试水小程序生态,我们iOS组抽了两个人组成小组做技术验证,最终选型是uniapp,因为团队里有人有Vue2的经验,而且当时uniapp已经支持了一套代码编译到微信小程序和H5两端,性价比不错。但这段时间也让我深刻理解了"跨平台框架的抽象是有代价的"这句话。
第一个坑是真机调试时自定义组件的原生渲染问题。有时候在H5端表现正常的功能,编译到微信小程序端就失灵,比如scroll-view的下拉刷新在iOS上有时候会跟页面级滚动产生冲突。第二个坑是性能瓶颈。uniapp的列表渲染在小程序端依赖setData同步数据,数据量一大(比如超过1000条),页面就明显卡顿。后来我们用分页加载、虚拟滚动、节点缓存等方式勉强解决,但本质上是框架自身的渲染链路决定了性能上限。第三个坑是平台差异化逻辑。uniapp的API封装层看着很美好,但真到调用相机、蓝牙、定位等原生能力时,你还是得用条件编译去区分微信、App、H5三端,代码里写一堆#ifdef,可读性和维护性直线下降。
但客观地说,对于展示类、低频交互、内容型的小程序,uniapp的性价比确实很高。我们那个项目最终从原型到上线只用了三周,如果纯原生开发,光微信端的适配和审核就得再多一倍时间。跨平台方案不是万能灵药,也不是洪水猛兽,关键是选对场景。
3.3 鸿蒙来了,多端开发会怎么走
这个话题在2024年后变得非常现实。鸿蒙系统从诞生之初的"兼容安卓生态"到NEXT版本彻底剥离AOSP代码,走完全自研的技术路线,App需要基于ArkTS和ArkUI重新开发。对iOS开发者来说,这既是挑战也是机会。
挑战在于:你过去十年的积累在鸿蒙生态里归零,Swift和OC的知识完全用不上,要重新学习ArkTS的声明式语法和方舟编程框架,心态上很容易失衡。机会在于:鸿蒙生态处于急速扩张期,市场对鸿蒙开发者的需求远大于供给,懂原生开发思维、对移动端底层机制有深刻理解的开发者,迁移到ArkTS会比纯前端背景的开发者更快掌握。我在2024年用业余时间学了鸿蒙开发,发现里面的状态管理、组件化思想、生命周期管理,和SwiftUI几乎是一个路数。你只要理解了声明式UI的核心理念,这套东西上手是很快的。
另外一个趋势是多端统一的理想正在以"C-S架构"的形态回归:代码不追求一次编译到处跑,而是通过云侧统一逻辑、端侧做轻量适配。苹果的SwiftUI、谷歌的Flutter、鸿蒙的ArkUI都在往"一套代码映射多设备"的方向演进,但底层实现路径完全不同。我认为未来很长一段时间内,移动端都会是原生、跨平台、操作系统厂商自研框架三足鼎立的局面。作为开发者,与其纠结学哪个,不如抓住这几个系统的共通点:状态管理、渲染原理、布局系统、生命周期。这些底层的思维模型一旦打通,切换技术栈只是熟悉API的体力活。
4. 那些年一起踩过的坑:审核、性能与兼容性
4.1 App Store审核的玄学与科学
做iOS开发绕不开App Store审核。网上流传着各种玄学,什么"周五提交更容易过""凌晨提交审核快",我实测下来,这些说法大部分是幸存者偏差。真正影响审核结果的是你有无触碰到平台的红线。
我用自己的血泪史总结了几个高频被拒原因:
- 隐私权限描述不具体。比如你申请相机权限,却只写"需要相机权限",苹果会拒,要求你说明使用场景。标准写法是"用于拍摄头像照片以完成用户注册"。
- 使用了私有API。这在大厂内部代码里非常常见,尤其在做性能监控、热修复、统计埋点时容易踩线。苹果的静态扫描越来越严格,一旦被识别为使用私有API,轻则警告重则下架。
- 应用内购买(IAP)不合规。凡是iOS端App内解锁数字内容或服务,都必须走苹果的IAP支付。很多团队想绕过抽成使用第三方支付,一旦被检出,封号都是可能的。
- 页面截图或文案包含其他平台的名字。我们曾因为App内有一个"关注我们的安卓版本"提示,直接被判定为异常引导,要求整改。
审核经验总结成一句话就是:把苹果当成一个特别注重用户体验、且对违规零容忍的苛刻用户,开发全过程都以它的视角审视产品,这样能减少90%的审核麻烦。
4.2 性能优化:从卡顿到流畅的实战
性能优化是iOS开发中永不过时的话题。十年下来,我做性能优化的思路从"问题出现了再解决"变成了"架构阶段就为性能铺路"。最常见的三个性能杀手是:主线程卡顿、内存泄漏和启动时间过长。
主线程卡顿的根源通常是大量耗时操作阻塞了UI渲染,比如数据解析放主线程、大量图片的同步解压、频繁的View层级操作。排查套路很成熟了:用Instruments的Time Profiler定位耗时函数,用Xcode的Main Thread Checker发现主线程调用了后台线程才允许的API。解决手段也很固定:把耗时操作挪到子线程、使用异步绘制、对集合视图做预布局和复用优化。
内存泄漏则更隐蔽。Block循环引用、NSTimer未销毁、通知未移除、闭包捕获self,每个都是老生常谈但每个人都犯过。我在2020年后开始在团队推行Swift的weak self显式声明规则,配合Xcode的Leaks检测和Malloc Stack标记,内存问题终于从"靠经验猜Bug"变成了"可定位可复现"。
启动时间线是最容易被忽略的性能指标。App冷启动时间超过两秒,用户流失率会明显上升。优化启动的核心在于精简启动时加载的静态库、延迟非首屏必需的服务初始化、使用二进制重排优化虚拟内存缺页。我们在一个项目中把启动时间从2.8秒压到了1.2秒,你觉得难吗?其实只是把十几个第三方SDK从启动阶段懒加载,产品体验立刻上一个台阶。
4.3 适配地狱:刘海屏、灵动岛与各版本系统
苹果的硬件迭代和系统升级,是每个iOS开发者心里永远的痛。2017年iPhone X带火了刘海屏和圆角全面屏,一时间所有App的布局都出问题:状态栏高度从固定的20pt变成了变化的44pt(后来还有动态岛和灵动岛的59pt),安全区域的适配从"Hack样式"正式进入了"Safe Area Layout Guide"时代。
我总结了一套自己的适配方法:代码里永远不要写死状态栏高度和TabBar高度,统一使用safeAreaInsets和safeAreaLayoutGuide,配合Auto Layout的约束系统处理。如果你还在用frame布局,那几乎每个新机型发布都会让你崩溃一次。2022年灵动岛发布后,我们在适配时发现一个有意思的坑:Live Activity(实时活动)的API虽然方便,但它的UI布局空间极其有限,动态文字一长就被截断,必须做专门的压缩显示逻辑。
系统版本适配同样折磨人。iOS 13的深色模式普及让我们所有硬编码的颜色全部暴露,不按照动态UIColor适配的界面在深色模式下惨不忍睹。iOS 14新增的桌面小组件带来了新需求但开发成本不低。iOS 16的锁屏小组件又是另一套逻辑。iOS 18和19在隐私保护上持续加码,权限申请和追踪透明度成了新的适配重点。你可以抱怨苹果的规则变来变去,但换个角度想,这些"折磨"正是iOS开发者这个岗位存在的意义——如果一切都标准化到无需适配,那还需要我们来做什么呢?
5. 十年开发者的职业思考:从写码到带团队
5.1 技术人如何对抗焦虑
这十年,iOS开发者的焦虑感其实一直在增加。每隔一两年就会出现一个"XX技术要取代原生"的论调,每隔三五年就会有一批开发者被行业洗牌。我身边转行的、考公的、上岸的、做自媒体的,什么人都有。我自己也经历过无数次深夜焦虑:会不会被Flutter抢走饭碗?要不要转后端?三十多岁了还写代码是不是不行?但回头看,焦虑的根源往往不是技术变化本身,而是对技术变化缺乏应对的从容感。
我个人的应对策略是"T型能力"建设。纵向深耕iOS领域,把性能优化、架构设计、底层原理掌握到团队里没几个人能比的程度,这是护城河。横向拓展跨平台开发、小程序技术、产品思维、项目管理,这是抗风险能力。当你的能力结构不再依赖某一个具体技术栈时,技术变迁对你来说就只是工具切换,而不是职业危机。
另一个心得是:不要只埋头写代码,要定期输出。写博客、做分享、带新人、参加技术社区活动,这些行为本质上是在强迫你梳理和验证自己的知识体系。我在2019年开始系统地做技术分享和文档沉淀,坚持了五六年下来,发现最大的受益者不是听众,而是我自己。教是最好的学,这话真不虚。
5.2 我给年轻开发者的几点建议
带过几十个新人后,我发现很多年轻iOS开发者走的弯路都惊人地相似。这里捡几个最重要的建议分享给刚入行不久的朋友:
第一,先做深再做宽。刚入行的前两三年,一定要选择一个具体方向(比如性能优化、架构、底层框架)钻研到足够深。整个行业不缺什么都会一点的通才,缺的是在某个方向能解决真实复杂问题的人。我见过太多工作三年却像工作一年的简历,就是因为一直在各个技术栈之间跳来跳去,哪个都没深入下去。
第二,动手前先理解原理。用Masonry、SnapKit、SwiftUI,别只知道调API,要理解它们的底层实现。自动布局的约束求解过程、SwiftUI的依赖追踪机制、Combine的背压概念,这些看起来"理解了也不影响调API"的东西,才是你和普通开发者的分水岭。
第三,保持对产品和商业的感知。纯技术的视角会让你的职业天花板很低。多想一想你的代码为产品带来了什么,为什么这个按钮要放在这里,这个功能为什么要砍掉,用户的流失点在哪里。当你开始用产品经理的思路去思考技术问题时,你才真正具备了向高级别发展的潜力。
第四,接纳并拥抱新平台新语言。从OC到Swift,从原生到跨平台,从移动端到多端统一,每一次变化都是行业格局的重构。重构意味着旧的秩序被打破,但同时也意味着新位置空出来了。2019年SwiftUI刚出来时,很多人嘲笑它不成熟,但坚持投入学习的人,现在已经是团队里SwiftUI方向的核心骨干。对新事物保持开放和好奇,是技术人最值得的投资。
写在最后
写完这些,心里其实挺感慨。十年前我是一个对着Xcode报错日志干瞪眼的新人,十年后我可以坦然地跟团队说"这个性能问题按这套思路查一定能解决"。时间在技术上留下的痕迹很明显,Swift从1.0走到了6.0,iPhone从6s换到了18 Pro,行业从纯原生打天下变成了原生与跨平台分庭抗礼。但有些东西一直没变:把用户体验放在心尖上的那份坚持,对代码质量近乎偏执的追求,以及深夜调通一个顽固Bug之后的如释重负。
如果一定要给这个十年配一句话,那就是:在这个行业里,别把自己定义成"某个平台上的开发者",要把自己定义成"能解决移动端复杂问题的人"。平台会更换,技术会迭代,但你解决复杂问题的能力和沉淀下来的思维模型,永远是跟着你自己走的。
最后分享一个我一直在用的小技巧:每年年初,翻一遍苹果的Human Interface Guidelines和最新的What's New文档,再挑一个以前没深入过的系统框架(比如Core ML、Vision、Metal)做个Demo。这个小习惯我坚持了八年,它保证了我的技术视野始终在行业前沿,不至于被突然的变化打懵。今天把这些写出来,也是想告诉2015年那个刚入行的自己:这十年,路没走错。