做iOS开发到今年正好十年。2015年入行的时候iPhone 6s刚发布iOS 9到处都在讨论代码还是清一色Objective-C十年后再看我自己做过纯原生App也写过uniapp和微信小程序面试过大量iOS开发也填过无数只有iOS才有的深坑。这篇文章不打算写成励志故事就是趁这个节点把十年里攒下的技术底子和那些踩过的坑好好盘一盘。如果你正在学iOS开发或者做了几年正在纠结要不要转型这篇应该能给你一些实在的参考。内容会比较长我尽量挑干货讲。1. 十年iOS开发路从Objective-C到Swift再到全面拥抱跨端1.1 语言层面的三次跨越2015年那会儿入行第一道坎就是Objective-C。现在回头看我依然觉得Objective-C是一门被低估的语言它的消息发送机制、runtime、block都深刻影响了后面我对iOS框架的理解。很多人觉得方括号调用方法很土但正是这种动态性让iOS在运行时可以做非常多的事情比如Method Swizzling、动态添加方法、KVO这些在后来的面试和实际排查问题里都会反复遇到。如果你现在刚开始学iOS建议还是抽时间了解一下runtime的基本流程消息是怎么发送的、怎么查找IMP、找不到会怎么处理这些不是面试官拿来刁难你的而是你真正遇到一些疑难Bug时的救命稻草。第二道坎是Swift。Swift 1.0时代我身边愿意切的人不多语法一天一个样第三方库也不全。但到了Swift 2、3之后苹果明显稳下来了Swift 4以后基本可以在生产环境放心用。十年来Swift最大的变化就是并发编程async/await和actor的出现让异步代码终于不像以前那样嵌套地狱。我记得第一次把一段回调套回调的网络请求改成async/await的时候整个人都舒服了。对新手来说Swift现在的学习曲线其实比当年Objective-C友好太多但我建议别只学语法要理解Swift的值类型、引用类型、内存管理和访问控制这些决定了你写的代码在复杂场景下稳不稳。第三道坎很多人没意识到是JavaScript和TypeScript。2017年前后小程序开始普及后来uniapp这类跨端框架又火了起来做iOS的人都得面对一个现实很多业务不再要求你写纯原生而是用一套代码跑小程序、App、H5。我做跨端项目初期非常抗拒觉得这是对原生开发者的降维打击但后来想通了语言只是工具重要的是你在iOS上积累的那套对系统行为、性能、适配的理解放到任何端都值钱。你可以抱怨但不能不学否则连问题都定位不了。1.2 系统适配是一场没有终点的长跑这十年iOS系统版本从iOS 9一路走到今天的大版本中间有很多影响深远的节点iOS 10开始强制ATS让全行业被迫上HTTPSiOS 11改了大标题和状态栏布局逻辑iOS 13带来深色模式所有App的适配工作又多了一轮iOS 14开始隐私权限收紧IDFA要弹窗授权iOS 16改了锁屏交互和开发者模式再往后是灵动岛、实时活动这些硬件交互变化。每次系统大版本发布开发团队的适配清单基本都要排一两周。硬件的适配就更有意思了。我从iPhone 6的大屏适配做起然后iPhone X的刘海屏和安全区、iPhone 14 Pro的灵动岛、iPad的分屏多任务每一代都在考验你对布局的敬畏心。十年来我最大的心得就是不要写魔法数字不要依赖某一个机型的宽高要相信系统的安全区、约束布局和自适应布局。你用固定坐标码出来的界面在某个新机型上一定会出问题只是时间问题。系统版本管理也是开发者绕不开的话题。很多人搜“iOS延迟升级”其实不一定是灰色操作开发团队很常见的做法是给测试机安装描述文件锁定系统版本或者谨慎评估后再升级因为一旦测试机系统升上去有些老设备或老接口可能就回不去了。另一个常见问题是“高版本备份恢复到低版本”这个在iOS上基本是走不通的高版本的备份格式和数据库字段低版本不兼容硬刷回去大概率报错只能接受数据迁移的现实。从我自己的实践来说测试团队的系统版本一定要错开分布不能全员最高版本也不能全员不升否则兼容性盲区很大。2. 跨端与小程序那些把iOS认知重写一遍的项目2.1 用uniapp做跨端收费问题先搞清楚网上经常有人问“uni-app打包iOS收费吗”这个问题我当面回答过很多次。uniapp本身是开源免费的用HBuilderX做本地打包、用源码工程跑Xcode也都是免费的。它说的收费主要指着云端打包服务如果你不想本地搭环境直接用DCloud的云打包并且用的是他们的公共证书那确实有次数或服务上的限制要想稳定就得买他们的套餐或者自己出Apple开发者证书。换个说法只要你手上有自己的Apple开发者账号自己在Xcode里构建、签名、上传App Store这条路是不需要向uniapp官方付费的。但比收费更值得关注的是跨端项目在iOS上的适配成本。uniapp在iOS端的底层是WKWebView加原生组件混编很多前端正常的代码在iOS上表现不一样比如键盘弹起把按钮顶起来、canvas导出白图、文件下载变成预览这些我后面会专门说。我的建议是不要把uniapp当成“一套代码全端通吃”的银弹它有非常明显的价值就是开发效率和动态发布但你必须在每个iOS大版本发布后做一轮真机回归。跨端项目节省的是重复开发时间省不了的是设备适配和真机测试。2.2 小程序里那些iOS特有问题微信小程序在iOS端的坑做过的都知道比安卓多不少。一个典型问题是“静音状态下播放音乐”。iOS的静音开关会影响音频会话很多时候你在安卓上能正常播放的音频到iOS一旦用户把静音键打开就没声音了。要解决这个问题不能只调用播放接口还要在用户手势回调里先激活音频会话、设置正确的播放分类比如playback模式让声音不受静音键控制。微信小程序里还有自己的音频管理器有时候还要手动resume音频上下文。这个坑的本质是iOS的音频会话机制不理解它就容易被表面现象带偏。另一个高频问题是“iOS机型网络请求失败率高”很多团队会拿一个类似6001的错误码来排查。说实话错误码只是线索真正的排查链路是先看证书链是否完整、域名是否支持ATS和IPv6再看是不是弱网下的超时策略太激进最后用抓包工具对比成功和失败请求的完整链路。小程序里还经常出现iOS WebView缓存导致页面异常的情况典型的就是公众号H5重复刷新。这个问题有的是因为WKWebView的历史记录和JS执行时机叠加导致重复load有的是Cookie同步策略变更。排查思路是先把自动刷新逻辑关掉逐步打开开关定位再用Safari的Web Inspector看页面生命周期和请求记录。2.3 跨端项目的设备兼容策略做跨端之后我才意识到iOS开发者以前那种“只关注iOS”的时代真的过去了。现在一个需求落地可能同时涉及iOS原生、小程序、H5、安卓、鸿蒙。我的做法是建立一份兼容性清单把每个端的已知差异列出来。比如iOS上textarea聚焦弹键盘会遮住按钮、canvas离屏绘制有概率白图、Safari对某些文件类型只预览不下载安卓上字体渲染偏大、返回键行为要单独处理小程序里要小心原生组件层级鸿蒙上又要重新验证一遍基础能力。这份清单不是一次性的每个大版本系统更新都要回来补几条。3. 高频踩坑清单H5与原生交互的最后一公里3.1 textarea输入层盖住按钮别再甩锅给系统“iOS textarea输入出现层盖住了按钮”这个问题的搜索量一直很高说明它是跨端开发者的共同记忆。现象很明确页面底部有个输入框旁边或者下方有提交按钮在iOS里一点输入框键盘弹起来按钮就被顶起来或者直接遮住等键盘收回去按钮的位置还错着点也点不准。根本原因得从iOS WebView的键盘处理逻辑说起。iOS WebView弹出键盘时会把可视视口压缩原本fixed定位到底部的元素会被键盘顶上去这其实是系统为了让你能看到正在输入的内容。麻烦的是键盘收起的动画和页面布局恢复不是同步的失焦那一刻按钮可能还在原来被顶起的位置就出现了“遮挡残留”。我把解决方案分了三层第一层是布局上的不要对底部按钮用简单的fixed定位而是监听可视视口高度变化动态设置按钮的位置第二层是交互上的失焦后不要立刻做复杂操作延迟几十到几百毫秒等键盘动画结束再滚动到安全位置第三层是组件上的在一些跨端框架里可以用原生组件覆盖层比如小程序的cover-view绕开浏览器布局恢复的Bug。我自己最常用的组合是“position: fixed改为absolute 监听blur延迟重算 必要时滚动到底部”。3.2 Safari里canvas导出白图另一个让我印象很深的是“iOS Safari 使用 uniapp canvas 队列时导出白图”。当时做一个批量生成图片的功能用canvas画完一张导出base64再画下一张结果在iOS Safari里总有一部分图片导出是白图安卓完全正常。排查了很久最后发现是Safari对canvas做了性能优化当canvas不在可视区内或者绘制任务还在队列中调toDataURL时拿到的图像数据是空的。解决办法有几个比较管用一是画布在导出前要保证它在页面可视区域内即使把它固定到角落也可以二是绘制完成后不要立刻导出先延迟一小段时间确保绘制队列执行完三是优先用新版canvas 2d接口能力更稳定四是检查canvas的width和height有的框架里样式宽高和绘制宽高不一致会导致导出空白。跨端框架里做canvas批量导出的时候我最后还封装了一层队列控制每张图导出完再等100毫秒进入下一张问题基本绝迹。3.3 H5下载文件变成预览的问题“H5在iOS下载文件变成了预览”这也是个经典场景。你在页面上放了个下载按钮点完安卓直接下载iOS却把PDF或图片在浏览器里打开了。原因是iOS Safari对很多MIME类型默认走预览逻辑它认为展示比下载更符合用户体验。要强制下载服务端响应头里得带Content-Disposition: attachment这样Safari才会把它当下载处理。如果服务端没法改前端可以用Blob把文件拉下来再通过a标签带download属性触发下载。但这里有个坑iOS Safari对跨域download属性支持有限有时候必须先把文件转成Blob URL再临时创建链接下载完成后再回收。一些文件类型像视频和图片在iOS上直接走“保存到相册”会更顺手那就需要用到系统级的分享能力这在原生App和小程序里都有对应的API。3.4 这些坑背后其实是同一件事把textarea遮挡、canvas白图、文件预览这些坑放一起看你会发现它们都指向同一个本质iOS WebView对页面交互的接管比安卓激进得多它在键盘、渲染、文件行为上都有一套自己的默认逻辑。做跨端开发与其等症状出现再去搜答案不如提前把iOS WebView的行为差异列成清单在方案设计阶段就避开。相信我这几类问题在项目里出现的频率远比你想的高。4. 调试工具与开发环境十年磨出来的高效工作流4.1 charles抓包到底怎么用做iOS开发抓包是基本功。Charles是我用得最顺手的工具先说基本流程第一步在电脑上装好Charles并启动第二步让手机和电脑连同一个Wi-Fi把手机代理指向电脑的IP和默认端口第三步安装并信任Charles的根证书第四步在Charles里开启SSL Proxying把要抓的域名加进去。这里有几个版本的坑要注意iOS 10之后证书装完必须去“设置-通用-关于本机-证书信任设置”里手动信任iOS 14之后App要访问本地网络还得在设置里开启本地网络权限不然抓不到iOS 16之后真机调试和抓包都需要先在手机设置里打开开发者模式。抓包最常见的挫败感是“装了证书还是抓不到HTTPS”。先别急着怀疑工具按顺序检查代理有没有生效、证书有没有信任、目标域名有没有加进SSL Proxying、App是不是用了SSL Pinning。最后一种是应用主动做了证书绑定Charles这类中间人代理会被识破。这里我想多说一句很多团队到处搜“某App怎么抓包”不如反过来把精力放在自己App的安全防护上。SSL Pinning是iOS开发里很实用的安全手段做法是把服务端的公钥或证书哈希固定到客户端校验不通过就拒绝连接。这个机制对拦截中间人攻击很有效但也给调试增加了成本所以工程上一般都是debug环境关掉、release环境开启。4.2 开发者模式、真机调试与系统版本管理从iOS 16开始真机调试多了一道门槛必须在手机上打开开发者模式否则Xcode会提示找不到设备。这个位置在“设置-隐私与安全性-开发者模式”打开之后会重启手机。很多新人第一次被卡在这里其实不是代码问题就是没开这个开关。系统版本管理上我的原则是开发主力机可以追新但测试用机一定要有一台保持老系统哪怕它是五年前的机型。这就是为什么很多人要找旧版软件或老系统镜像不是为了别的就是为了兼容性测试。iOS的备份机制有个硬性限制高版本备份无法恢复到低版本设备。你手机升到新系统之后备份的数据想恢复到旧系统上基本都会被拒。所以在做升降级测试前一定要确认备份的兼容性避免数据丢失。另外升级系统前最好看看主流第三方SDK的兼容性公告很多崩溃都是系统升级后SDK不适配造成的。4.3 自动化、设备模拟与唤起App自动化测试这块我大概从2018年开始认真做。XCTest的UI测试可以模拟用户点击、滑动、输入适合做核心路径的回归。配合Fastlane可以把打包、签名、上传、发版这一串动作在一条命令里跑完。这些年CI跑自动化给我省了不少事但也得提醒一句UI自动化用例很脆系统弹窗、网络波动都能让它挂一定要做重试和失败截图不然天天被报警烦死。设备模拟也很重要。Xcode的Simulator不仅能模拟不同机型还能装不同版本的系统镜像适合快速验证布局。但有些能力模拟器做不了比如推送、相机、震动、某些传感器这些还是得上真机。另外做H5调试时iOS模拟器里的Safari可以直接用Mac的Web Inspector连上页面结构、网络请求、JS控制台都能看这个效率比在真机上调试高很多我强烈建议多用。“浏览器唤起安装App”是另一个常见的业务需求。老牌方案是URL Scheme但现在已经有很多限制苹果推荐的做法是Universal Links。它的原理是给App配置Associated Domains域名同时在服务器放一个apple-app-site-association文件浏览器遇到这个域名下的链接时如果手机上装了对应App就直接唤起没装就打开网页。这个机制设置起来不复杂但坑在配置文件必须走HTTPS、格式要严谨、更新不是实时的。我遇到过几次线上环境死活唤起不了最后发现是AASA文件没加Content-Type或者域名大小写写错了。5. iOS面试这些年基础题背后的真实考验5.1 面试官爱问的那些基础题这十年我面过不少iOS开发也经常在网上看“iOS基础面试”相关的总结。很多人把面试当背题但实际上面试官想考察的是你对系统的理解深度而不是记忆能力。比如问runtime消息传递不是要你背消息发送流程而是看你能不能解释Method Swizzling的应用场景、怎么动态添加方法、消息转发能解决什么问题问RunLoop是想知道你怎么用它解释主线程卡顿、autoreleasepool的释放时机、事件响应的来源。再比如block循环引用几乎是必问的。一个合格的iOS开发不仅要说清楚self被block持有、block又被self持有这个环还要能现场写出用weakSelf和strongSelf处理的方式并且解释为什么在block内部还要再strong一下因为执行过程中self可能被提前释放。Swift相关的面试重点会放在值类型和引用类型、内存安全、并发actor和Sendable、协议与泛型编程上。这些问题都有一个共同点表面上考语法实际上考的是工程思维能不能预判到代码在线上运行时的生命周期和并发问题。5.2 三类面试者的差距在哪面了这么多人我把他们大致分成三类。第一类是只写过页面、调用过API的常见问题是能说出使用的框架但说不清底层流程遇到崩溃只能重启这类在面试里会被问得比较难过。第二类是有意识读过一些源码、排查过线上崩溃的这类通常能讲清楚一两套完整的排查案例比如怎么通过日志和抓包定位一个网络兼容问题这是最有竞争力的部分。第三类是能反推系统设计意图的比如能从沙盒机制聊到安全边界从系统版本变更聊到适配策略从Swift的内存管理聊到iOS应用的稳定性保障这类不管做原生还是跨端都很有价值。我的建议是不管你在哪个阶段都要刻意去积累“排查案例”。网上搜到的经验是别人的只有自己从头到尾定位过的问题才是你的。面试时能讲出一个有开端、有分析、有回退、有验证的完整案例比背一百道题都管用。5.3 给年轻iOS开发者的几句话最后以一个做了十年iOS开发的身份给还在路上的朋友几句实在话。第一别把原生和跨端对立起来。未来几年多端并存是常态原生功底是你的底牌跨端能力是你的半径两者都有路走。第二要持续关注系统更新。每年新系统发布后第一时间把文档、稳定性变化和适配要点都过一遍这个习惯能帮你避免很多线上问题。第三把基础打牢。不管是做iOS还是转行做其他端、做前端操作系统、网络、内存、并发这些底层知识是通用的它们决定了你的上限。第四脸皮厚一点多和同行交流。很多坑不是我一个人踩过的是几千个开发者一起踩出来的你把这个经验记下来下次就能用上。十年时间iOS开发这个行业变了很多从纯原生到跨端、从Objective-C到Swift、从单纯做功能到还要懂隐私合规和安全防护。我个人最大的体会是这个领域一直在变但底层的思维方式和基本功从来没有变过。遇到问题先复现、再抓包、再查文档最后才是搜经验这个流程我用了十年依然有效率。希望这篇总结能帮你在iOS开发这条路上少走一些弯路多留一些时间去享受写代码本身。
阅读完成 · 觉得有帮助?