技术探索与实践解决方案:一个老iOSer的工具链自救指南
大家好,我是老K,干了6年iOS开发的老兵,从OC时代一路熬到Swift并发模型上线,见证了Swift如何从“玩具语言”变成我们每天离不开的生产力工具。目前在一家中型电商公司带一个小团队,已经在这个组干了快2年——说白了就是既写代码又背锅的那种。
最近几个月,我越来越觉得:工具决定下限,思维决定上限,但deadline决定你能不能活到明天。上周五晚上十一点,我盯着Xcode里那个该死的编译错误(又是模块循环引用),一边狂灌第三杯美式,一边反思:为什么每次重构都像在拆炸弹?为什么新人入职三天还在配环境?为什么我投简历时连自己的技术栈都说不利索?
于是,我决定搞点事情。这篇文章不是什么高屋建瓴的技术布道,就是一个被逼到墙角的老iOSer,如何用工具+流程+一点点自尊心,把日常开发从“人肉运维”拉回“专业交付”的实战记录。顺便,也为接下来可能的求职攒点谈资——毕竟,谁不想在面试时掏出一套自动化流水线而不是只会说“我会MVVM”呢?
起因:一次差点翻车的线上事故
去年双11大促前一周,我们新上的商品详情页突然在iOS 15.0以下机型大面积白屏。测试同学凌晨三点把我从梦中叫醒,Log里只有一行:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
经典野指针,毫无头绪。排查半天发现是某个第三方SDK在低版本系统上调用了async/await相关API导致崩溃。问题本身不难修,但整个过程暴露了我们的工具链有多原始:
- 没有自动化的兼容性测试
- 没有静态分析拦截危险API调用
- 新人提交的代码没人Review就合进主干
- 连Crash日志都要手动从Firebase里扒
当时真的想砸电脑。更扎心的是,隔壁Android组早就上了CI/CD流水线,连UI自动化都能跑。而我们iOS组还在靠“人肉守护”。
工具链升级:从手工作坊到流水线
痛定思痛,我拉着两个靠谱的同事,在不影响业务迭代的前提下,悄悄启动了“工具链现代化”计划。目标很朴素:让机器干脏活,让人专注写逻辑。
1. 本地开发体验:告别“在我机器上是好的”
首先解决新人入职第一天就崩溃的问题。我们用tuist替代了手动管理Xcode Project。虽然学习曲线有点陡,但一旦配置好,新增Target、管理依赖、统一Build Settings就变得极其清晰。
// Project.swift
let project = Project(
name: "ShopApp",
targets: [
Target(
name: "ShopApp",
platform: .iOS,
product: .app,
bundleId: "com.shop.app",
infoPlist: "ShopApp/Info.plist",
sources: ["ShopAssistant/Sources/**"],
dependencies: [
.target(name: "Core"),
.external(name: "Alamofire")
]
),
Target(
name: "Core",
platform: .iOS,
product: .framework,
bundleId: "com.shop.core",
sources: ["Core/Sources/**"]
)
]
)
配合.swiftlint.yml + pre-commit钩子,连空格和换行都给你管得明明白白。现在新人clone完项目,一条命令tuist generate && pod install,直接跑起来,再也不用问“为啥我编译不过”。
2. CI流水线:不让Bug过夜
我们搭了一套轻量级CI,基于GitHub Actions(便宜!免费额度够用!):
- 每次PR自动跑单元测试 + UI测试(用XCTest + SnapshotTesting)
- 静态扫描:用
Periphery检测无用代码,SwiftFormat强制格式化 - 危险API拦截:自定义脚本禁止在非iOS 15+ Target里调用
async let
# .github/workflows/ci.yml
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Run Tests
run: xcodebuild test -scheme ShopApp -destination 'platform=iOS Simulator,name=iPhone 14'
- name: Check Unused Code
run: periphery scan --project ShopApp.xcodeproj
- name: Block Async/Await on iOS < 15
run: |
if grep -r "async let\|Task {" Sources/ --include="*.swift" | grep -v "iOS15+"; then
echo "❌ Found async/await in non-iOS15 code!"
exit 1
fi
自从上了这个,线上Crash率降了40%。产品经理看数据都惊了:“你们最近是不是偷偷加了人?”
3. 文档即代码:别再用飞书文档糊弄事
我们把架构图、接口文档、部署流程全扔进了代码仓库,用DocC生成可交互文档。每次代码更新,文档自动同步。新人看一眼就能知道“用户登录模块怎么调”、“图片上传走哪个Endpoint”。
求职视角:工具链也是核心竞争力
说实话,这次折腾除了救火,还有一个私心:为跳槽做准备。
现在的iOS岗位,早就不只是问你“weak和unowned区别”了。上周面一家大厂,面试官直接问:“你们怎么保证代码质量?有没有自动化测试覆盖率?如何管理多Target依赖?”
要是我还停留在“手动打包+口头交接”,估计连二面都进不去。但因为我能拿出整套工具链方案,甚至展示了CI流水线的截图和性能对比数据,当场就拿到了offer意向。
下面是我们优化前后的关键指标对比:
| 指标 | 优化前 | 优化后 | 提升 |
|---|---|---|---|
| 新人上手时间 | 5天 | 1天 | 80% ↓ |
| PR合并平均耗时 | 2天 | 4小时 | 79% ↓ |
| 线上Crash率 | 1.2% | 0.7% | 42% ↓ |
| 自动化测试覆盖率 | 15% | 68% | 353% ↑ |
这些数字,比你说一百遍“我注重代码质量”都有说服力。
血泪教训 & 最佳实践
当然,过程也不是一帆风顺。分享几个踩过的坑:
别追求一步到位
一开始我想上全套:SwiftLint + SwiftFormat + Periphery + DocC + 自动化测试……结果两周过去,业务需求积压,被领导骂“不务正业”。后来改成“小步快跑”,每个迭代只加一个工具,先跑通再优化。工具要为业务服务,不是炫技
曾经为了用Swift Concurrency重写了整个网络层,结果发现iOS 13用户还有10%,只好回滚。现在我们定规矩:新技术必须有fallback方案。让团队参与进来
工具不是我一个人的玩具。每次引入新工具,都会开个小会讲解“它能帮你省多少时间”。比如SwiftFormat自动修复格式,程序员再也不用为缩进吵架——这比讲一百遍“代码规范”都管用。
写在最后
六年iOS,从手动拖控件到用DSL写UI,从纯OC到拥抱Swift并发,我越来越觉得:真正的工程师,不是只会写功能,而是会构建系统。
工具链建设看起来“不性感”,没有炫酷的动画,也没有复杂的算法,但它决定了你每天是焦头烂额地救火,还是从容不迫地交付价值。
如果你也在经历类似的困境——别等线上崩了才行动。花一周时间搭个基础CI,配个代码规范,可能就改变了整个团队的命运。
至于我?已经更新了简历,把“主导iOS工具链现代化,提升团队交付效率200%”写进了第一行。毕竟,在这个卷成麻花的市场里,会用工具的程序员,永远比只会敲if-else的人值钱。
对了,如果你们公司正在招懂工具链的iOS,简历可以发我邮箱(开玩笑的,但真的建议你试试)。

评论 0