技术探索与实践的五年成长路:从“搬砖”到“造砖”

◆李敏
2025-06-25 00:29
阅读 582

刚入行的时候,我总觉得技术就是解决问题的能力。写代码、调接口、改 Bug 就是全部。那时候每天都在想着怎么把产品经理的需求“翻译”成代码,很少停下来去想,“为什么这么做?”、“有没有更好的方式?”。直到几年后,我在一个大型项目中经历了架构升级、性能优化、跨团队协作等多个挑战,我才真正理解了什么是“技术探索与实践”。

今天我想借这篇文章,结合自己这几年的经历,尤其是最近参与的一个重要项目,聊聊我对这个话题的看法。


背景:一次性能翻车事件

背景:一次性能翻车事件

2019年我加入了一家电商类创业公司,当时的产品已经上线一年多了,用户量也逐步上涨。但由于早期开发节奏快、产品需求急,导致底层架构和模块划分并不清晰。随着业务不断增长,App 出现了一些不可忽视的问题,比如:

  • 首屏加载慢
  • 列表滑动卡顿
  • 多人协作容易冲突
  • 模块复用性差

有一次我们做了一个促销活动页面,结果上线当天用户一多,就开始出现大量 Crash 和 ANR(Application Not Responding)。这成了我职业生涯中的一个转折点,也是促使我去深入思考“技术探索”的起点。


问题:如何让 App 更流畅、更稳定?

问题:如何让 App 更流畅、更稳定?

面对这些问题,我们团队开始了一场“技术反思大会”,目标很明确:

  1. 提升用户体验(流畅度、稳定性)
  2. 提高代码可维护性(降低后期迭代成本)
  3. 构建一套可复用的技术方案(方便后续新业务快速接入)

当时的 iOS 开发主流还在使用 MVC 结构,但我们发现 ViewController 中堆积了大量的业务逻辑,甚至有些文件有上千行代码,完全无法阅读。UI 层、数据层、网络层严重耦合,修改任何一处都要小心翼翼,生怕牵一发动全身。

于是我们决定启动一项名为 Project Athena 的架构重构项目,希望通过这次机会引入 MVVM+Coordinator 模式,并在性能方面下一番功夫。


解决方案:架构重构 + 性能优化并行推进

解决方案:架构重构 + 性能优化并行推进

1. 架构设计选择:MVVM + Coordinator

我们选择了 MVVM 作为视图层的架构模式,配合 Coordinator 来管理导航逻辑。

📌 为什么要这样选?

MVC 是苹果官方推荐的,但实际开发中往往会造成 Massive View Controller;而 MVP 虽然解耦性强,但在 iOS 上实现比较繁琐;MVVM 更加适合 Swift + Combine/ViewModel 的响应式编程风格。加上 Coordinator 可以很好地管理跳转逻辑和生命周期,非常适合我们这种需要高度组件化、流程复杂的 App。

我们在项目中引入了如下结构:

├── Feature
│   ├── Home
│   │   ├── HomeViewController.swift
│   │   ├── HomeViewModel.swift
│   │   └── HomeCoordinator.swift
│   └── ProductDetail
│       ├── ProductDetailViewController.swift
│       ├── ProductDetailViewModel.swift
│       └── ProductDetailCoordinator.swift
├── Core
│   ├── NetworkManager.swift
│   └── PersistenceManager.swift
└── Shared
    └── CommonUIComponents.swift

每个功能模块都有自己的 Coordinator 负责导航流转,ViewModel 管理 UI 数据绑定,View 只负责渲染。大大降低了 ViewController 的复杂度。

2. 使用 SwiftUI 替代部分 UIKit 页面

为了进一步提升效率和可维护性,我们在一些新的业务线中尝试引入 SwiftUI。最初团队很多人不习惯声明式语法,甚至觉得写起来不如 UIKit 直接。

但经过几周磨合,大家发现:

  • 布局代码减少了很多
  • 实时预览调试效率极高
  • Binding、State、ObservedObject 这些机制特别适合做状态管理
  • 动画效果实现更加优雅简洁

后来我们做了个对比实验:两个工程师分别用 UIKit 和 SwiftUI 写一个相似的商品详情页,结果 SwiftUI 用时更短、出错更少,而且测试反馈说交互逻辑更容易理解。

3. 性能优化方向:内存 & 渲染优先级控制

除了架构层面的调整,我们还做了几个重点性能优化:

(1) 图片懒加载 & 缓存策略优化

早期使用的 SDWebImage 已经很成熟,但我们发现某些图片请求并没有合理缓存,尤其是在商品列表页频繁滑动时,会出现重复加载的情况。

我们做了以下优化:

  • 自定义缓存 Key,确保相同 URL 不会重复加载
  • 控制并发请求数,避免主线程阻塞
  • 滑动时暂停非可视区域的图片加载,停止滑动后再恢复
func configureImage(for url: URL?) {
    guard let url = url else { return }
    
    if isCellVisible {
        imageView.sd_setImage(with: url, completed: nil)
    } else {
        // 滑动中不加载图片
        imageView.image = UIImage(named: "placeholder")
    }
}

(2) 使用 Instruments 定位内存泄漏

通过 Instruments 的 Leaks 工具,我们发现了多个强引用循环,特别是在 Delegate、NotificationCenter、Timer 等地方没有及时释放。

解决办法包括:

  • 引用代理使用 weak
  • Timer 使用 scheduledTimer 并设置 repeats: false
  • 在 Deinit 中取消所有观察者注册

(3) 启用 App Thinning 和 Bitcode

为了让安装包大小控制得更好,我们启用了 App Thinning 和 Bitcode,根据设备类型自动分发最合适的二进制文件。这对冷启动速度也有明显帮助。


踩过的坑和经验总结

开发工具界面-1

坑1:过度设计导致初期效率下降

在项目初期,我们曾试图用协议驱动一切,甚至连 ViewModel 的数据源也全靠 Protocol 去抽象,结果导致:

  • 模板代码过多,学习成本高
  • 编译时间变长
  • 团队新人上手困难

后来我们做了一些精简,比如不再强制所有数据都走泛型或协议,而是只在真正需要解耦的地方才使用。回归“适度设计”的原则。

坑2:SwiftUI 与 UIKit 混编带来的兼容性问题

在混合使用 SwiftUI 和 UIKit 时,我们遇到了以下几个问题:

  • UIViewControllerRepresentable 包装的控制器有时不会正确释放
  • 导航栈混用 UINavigationControllerNavigationStack 时行为不一致
  • 生命周期控制变得复杂

最后我们选择统一使用 SwiftUI(因为大部分业务是新做的),对遗留的 UIKit 页采用桥接方式慢慢过渡。

坑3:异步任务处理不当导致崩溃

有一次上线后收到很多崩溃报告,定位后发现是某个异步回调中访问了已经被释放的对象。

我们的解决方案是:

  • 所有异步回调使用 [weak self] 捕获上下文
  • 使用 OperationQueue 替代 GCD 做任务调度,便于管理依赖关系
  • 对于关键路径使用断言检测是否为主线程执行

效果与收益

经过三个月的重构和优化,我们的 App 在多个维度都有显著提升:

指标 优化前 优化后
首屏加载时间 3.5s 2.1s
ANR / Crash 率 0.8% 0.1%
新功能开发周期 平均 4 周 缩短至 2.5 周
单个 ViewController 平均行数 800+ 行 200 行以内

更重要的是,团队的协作效率提升了,文档更清晰了,新成员可以更快地理解架构逻辑和编码规范。


我的几点建议

技术概念图解-2

如果你也在经历类似的困境或者想要做一次技术跃迁,下面是我这几年踩坑总结出来的几点建议:

✅ 1. 不要为“设计模式”而设计模式

设计模式不是银弹,它只是手段。不要为了看起来高级而去强行套用 MVVM 或 VIPER,先搞清楚你的需求边界在哪里,再考虑该不该拆解、如何拆解。

✅ 2. 技术探索必须结合业务场景

脱离业务的技术升级就像空中楼阁,很快就会被打回原形。每次技术方案制定前,一定要问自己:“这个改动能给业务带来什么价值?”

✅ 3. 经常回顾和反思自己的代码习惯

我以前喜欢在 ViewController 里写一堆 extension 分隔方法,以为这样就能解耦。其实只是视觉上的整洁而已,本质还是 MVC 的臃肿。定期 review 自己的代码,看看有没有更好的写法,才能持续进步。

✅ 4. 学会使用工具定位问题

Instruments、Xcode 的 Memory Debugger、Thread Sanitizer 这些工具真的能帮你省下大量排查时间。别总想着靠日志打印来调试问题。

✅ 5. 保持对新技术的好奇心,但要理性判断时机

现在 SwiftData、Async/Await、TCA 架构等新兴技术层出不穷。我鼓励大家去了解、去试水,但不一定马上在主业务线上使用。可以在 side project 或内部 demo 项目中先行验证,确认其适用性和稳定性。


最后的感悟:技术是为了解决问题,更是为了创造可能性

回头来看,五年 iOS 开发让我明白一个道理:技术从来都不是最终目的,而是实现目标的工具。你掌握了多少种设计模式、写了多少行代码都不重要,重要的是你能不能用这些技术做出对用户有意义的产品。

我也从“照着文档写代码”的新手,成长为“能主动提出问题、设计方案”的开发者。技术探索的过程虽然很痛苦,但正是这些痛苦让我成长得更快。

希望这篇文章能给你带来一点启发。如果你正在面临类似的架构难题、性能瓶颈、团队协作问题,不妨静下心来,好好梳理一下业务逻辑和技术现状,找到属于自己的“最优解”。

共勉!🌟

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝