前言
距离上一次写博客已经过去 9 年了。回头看了一下最后几篇文章的时间,确实有点恍惚,时光荏苒这句话放在这里还挺合适。
这几年技术变化很快,尤其随着 AI 时代的来临,查资料、整理脉络、校对文字、补齐上下文的成本都低了不少。以前写一篇文章,很多精力会花在资料整理和表达打磨上;现在这些环节可以被工具分担一部分,反而更应该把项目里的问题、判断和思考沉淀下来。
所以接下来还是想把博客重新写起来,并且尽量不间断地继续更新。在继续写新的内容之前,先把过去几年写过的文章做一次总结和索引,也算是给这个博客重新接上线。
还有一个背景也需要提前说明一下:这些文章大部分写于 2014 到 2017 年,正好是读研+工作第一年,很多内容来自学习过程、Demo 实验和早期项目实践。现在再看,其中一些知识点、概念表达和工程判断肯定不够成熟,有些实现方式也已经被新的框架、语言特性或团队实践替代了。
所以这次整理旧文章,并不是想把它们包装成今天仍然先进、完整、值得照搬的方案。更准确地说,它们是一组当年学习路径的记录:我当时怎么理解 Objective-C、Runtime、Auto Layout、组件化、开源控件这些问题,又是怎么通过写文章把零散经验沉淀下来的。
之前写文章的时候基本都是遇到一个问题、做了一个控件、踩了一个坑,然后顺手整理出来。时间长了以后,单篇文章之间其实是有脉络的:有些是 iOS 工程结构,有些是 Runtime 和内存管理,有些是 UI 交互和开源控件,还有一些是读书笔记、翻译和服务端相关的小实践。本文就把它们按主题重新整理一下,方便以后自己回头查,也方便刚好搜到某一篇的同学顺着同一类问题继续看下去。不过阅读时也建议带着一点历史视角:把它们当作参考和记录,而不是最新实践指南。
先说明:这是学习档案,不是最佳实践合集
目前博客里的旧文章主要集中在 2014 到 2017 年,一共 42 篇。现在回头看,这些文章当然带着很明显的时间痕迹:Objective-C、Masonry、CocoaPods、早期 Swift、Runtime、反编译,这些都是当时做 iOS 开发绕不开的话题。
不少具体写法现在已经不建议直接照搬了。比如早期对目录结构、网络层、宏、Category、CocoaPods 私有库的理解,都有很强的时代背景和个人经验色彩;一些控件实现也更多是为了学习绘制、布局、交互和 API 设计,不一定适合直接放进今天的生产项目。
但很多问题本身并没有过时,只是换了技术栈和工具形态。比如代码怎么拆、接口怎么设计、复杂页面怎么优化、遇到奇怪问题怎么验证,这些到现在依然是工程里每天都会遇到的事情。旧文章的价值更多在于记录当时的思考过程,而不是给出最终答案。
大致按年份看:
- 2014 年,主要是刚开始写 Blog,以及一个 Android 开源控件。更多像是“开始动手记录”的阶段。
- 2015 年,文章最多,覆盖了 iOS 项目结构、Objective-C 基础、UITableView 性能、GCD、Auto Layout、Runtime、Swift 控件等。很多内容是边学边用、边用边写。
- 2016 年,更多是在总结工程化、模块化、代码组织、API 设计,也有一些更底层的内存管理和消息发送内容。这个阶段开始尝试从单点问题往项目结构上看。
- 2017 年,主要集中在 Runtime、反编译、Xcode Bug 分析,以及几个控件和工具库。相比前几年,验证和分析的意识会更强一些。
如果按阅读路线来分,则可以这样看:
- 想看 iOS 工程实践,可以先看项目结构、模块化、代码组织。
- 想看 Objective-C 底层,可以从
@autoreleasepool、__autoreleasing、objc_msgSend、methodSignatureForSelector:这几篇开始。 - 想看 UI 实现,可以看 Auto Layout 系列、UITextView 图文混排、几个 TTG 开源控件。
- 想查具体问题,就直接按下面的主题索引找。
工程结构与协作:早期对项目边界的理解
这一类文章主要讨论“代码应该怎么放、怎么拆、怎么协作”。很多观点放到现在不一定是唯一答案,但是问题本身一直存在:项目变大以后,如何让代码还能被理解、修改和复用。
这里要特别注意,里面不少做法更像是当时从学生项目、小团队项目里摸索出来的经验。比如目录怎么分、Model 怎么命名、网络接口层怎么封装,这些今天可能会被更成熟的架构、模块化工具、代码生成、依赖管理和团队规范替代。它们的意义不在于“标准答案”,而在于记录当时如何开始意识到边界和职责。
-
iOS项目的目录结构-原创
比较早的一篇工程结构整理,重点是从目录层面把业务、工具、资源、第三方代码分清楚。 -
Entity和Model的不同-关于代码的数据层
讨论数据层对象的职责边界,适合和后面的 ViewModel、数据加工、接口返回设计一起看。 -
利用NSProxy实现消息转发-模块化的网络接口层设计-原创
从NSProxy和消息转发切入,把网络接口层做成更清晰的调用入口。 -
对组件化与模块化的思考与总结
当时读了不少组件化文章后做的一次整理,重点是“模块”和“组件”的区别,以及如何从业务、技术、界面、数据几条线去拆分。 -
总结一些iOS项目中组织代码的方法
从 CocoaPods 私有库、Carthage、Xcode Group、Category、#pragma mark等不同粒度整理代码组织方法。 -
API返回结果设计经验与总结
虽然分类放在服务端,但本质也是客户端和服务端协作的接口契约问题。 -
一次审核被拒的经历-关于iCloud到底应该备份什么数据
一个偏实践的审核问题,记录了 iCloud 备份数据边界,属于踩坑型文章。
Objective-C、Runtime 与内存管理:从好奇到验证
这一组文章是我自己回头看时比较有连续性的部分:一开始是内存和属性行为,后面慢慢过渡到 Runtime、消息转发、反编译和系统实现。
这部分现在再看,有些表达会显得比较稚嫩,甚至会把一些概念讲得不够严谨。但它们保留了一个学习过程:先被某个现象吸引,再写 Demo 验证,然后尝试从 Runtime、汇编或系统行为里找解释。即使某些结论今天需要重新校准,这个“先验证再总结”的习惯还是值得保留的。
-
NSString的Copy与内存分配
从NSString、NSMutableString的copy行为入手,看对象拷贝和内存分配。 -
@autoreleasepool-内存的分配与释放
整理@autoreleasepool的基本行为,是后面看__autoreleasing的基础。 -
结合访问Out Parameters出现EXC_BAD_ACCESS的例子,反编译汇编解读__autoreleasing
通过 Out Parameters 的 crash 例子,继续看__autoreleasing和 autorelease pool 的关系。 -
翻译-为什么objc_msgSend必须用汇编实现
一篇翻译文章,但对理解 Objective-C 消息发送、寄存器、调用约定很有帮助。 -
用Runtime的手段填充任意NSObject对象的nil属性
一个用 Runtime 遍历属性并填充默认值的小实践,适合理解属性列表和动态处理。 -
解决iOS项目的版本兼容问题-结合宏、Category和Runtime
用宏、Category、Runtime 做版本兼容处理,属于工程实践和 Runtime 的交叉。 -
在对象dealloc的后期执行Task-开源库TTGDeallocTaskHelper
围绕对象销毁阶段执行任务,涉及生命周期、关联对象和封装方式。 -
反编译分析Xcode8的Bug, release下连续两次调用有二级指针参数的空方法会Crash
一个比较典型的“写 Demo 验证 -> 反编译分析 -> 总结原因”的问题排查过程。 -
反编译分析并模拟实现methodSignatureForSelector方法
从methodSignatureForSelector:的行为差异出发,最后尝试模拟实现,适合作为 Runtime 深入阅读的一篇。
并发、性能与小技巧:项目经验的早期切片
这一类文章更偏“项目里马上能用到”的经验。现在很多技术栈已经变化了,但里面的一些判断方式仍然有参考意义,比如提前计算、缓存、减少重复创建、明确线程上下文等。
当然,这里的性能优化和技巧也有明显的时代局限。当时的设备性能、系统版本、UI 写法、网络层封装方式和今天都不一样,所以更适合看思路,不适合把每个技巧原样搬过去。
-
提升UITableView性能-复杂页面的优化
从复杂动态页面入手,总结 Cell 复用、高度缓存、数据预处理、View 缓存等优化点。 -
GCD使用经验与技巧浅谈
对 GCD 常见使用方式做了一次整理,包括队列、同步异步、延迟执行等。 -
为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权
一个更细的问题:如何给 GCD 队列绑定 Objective-C 对象,并正确处理内存管理权。 -
Block类型变量-缓存Http请求与回调
通过 Block 保存回调,解决重复请求和回调分发问题。 -
有关宏定义的经验与技巧-简化代码-增强Log
记录了一些宏定义用法,重点是让重复代码更少、调试信息更清楚。
UI、布局与交互实现:从效果反推代码
这一组基本都是“先有一个效果,再拆解实现”的文章。相比纯理论,我自己更喜欢这种写法:先把画面、交互、约束关系摆出来,再一点点推到代码。
这些文章里会出现 Masonry、手写布局、UITextView 图文混排、QuartzCode 这类很有年代感的内容。它们未必代表今天最推荐的 UI 实现方式,但对理解约束、绘制、文本附件、动画拆解仍然有帮助。
-
UITextView编辑时插入自定义表情-简单的图文混编
记录UITextView中插入自定义表情的基础实现。 -
UITextView编辑时插入自定义表情-续-自定义表情图片的大小
继续处理NSTextAttachment图片大小的问题,是上一篇的补充。 -
有趣的Autolayout示例-Masonry实现
Auto Layout + Masonry 系列第一篇,用有趣的布局示例解释约束。 -
有趣的Autolayout示例2-Masonry实现
Auto Layout 系列第二篇,继续通过示例练习约束关系。 -
有趣的Autolayout示例3-Masonry实现
Auto Layout 系列第三篇。 -
有趣的Autolayout示例4-Masonry实现
Auto Layout 系列第四篇。 -
有趣的Autolayout示例5-Masonry实现
Auto Layout 系列第五篇,也是这个系列后面的一次补充。 -
用QuartzCode快速实现一个收藏动画
通过 QuartzCode 快速做收藏动画,重点是工具生成动画代码后的理解和使用。
开源项目与控件实现:当年练习封装能力的记录
这些文章基本都围绕一个具体控件或工具展开:为什么做、最终效果是什么、API 怎么设计、关键实现点在哪里。现在看起来,有些库可能已经偏老了,不过当时做开源项目时对封装、文档、Demo 的训练还是很有价值。
尤其是这些 TTG 开头的控件,现在再看肯定还有很多可以改进的地方:API 设计、Swift 版本、并发安全、可访问性、测试、文档完整度,都不能按今天的标准说已经足够好。但它们确实记录了我当时从“写一个能跑的控件”到“尝试把它整理成开源库”的过程。
-
Android开源库-LinkTextView-原创
早期的 Android 开源控件,用来处理文本中的链接点击。 -
Swift写的库-TTGSnackbar
一个 Swift 写的 Snackbar 控件,重点在交互展示和 API 封装。 -
Swift开源项目: TTGEmojiRate的实现
基于UIBezierPath、手势和绘制实现 Emoji 评分控件。 -
开源项目-TTGTagCollectionView
标签布局控件,适合看布局计算、数据源和代理 API 的设计。 -
Swift开源Mac App - BingWallPaper
一个 macOS 菜单栏应用,用 Swift 获取 Bing 壁纸并设置桌面背景。 -
开源项目-拼图验证控件TTGPuzzleVerify的实现
拼图验证控件,包含图片裁剪、遮罩、滑动验证等实现点。 -
在对象dealloc的后期执行Task-开源库TTGDeallocTaskHelper
既是开源库,也可以归到 Runtime 和对象生命周期相关内容里。
读书笔记与翻译:把输入变成自己的理解
这部分主要是阅读《Effective Objective-C》和技术文章后的整理。它们不算完整翻译,更像是把书里的点和自己的理解合在一起做记录。
这类文章的局限也很明显:当时理解深度有限,很多地方更偏摘录和转述。现在如果重新写,肯定会补更多上下文和工程例子。不过作为学习记录,它们还是能看到当时怎样把书本知识和项目经验接起来。
-
Effective-Objective-C-读书笔记-Item-1
Effective Objective-C 系列笔记开头。 -
Effective-Objective-C-读书笔记-Item-2
继续整理 Objective-C 基础概念。 -
Effective-Objective-C-读书笔记-Item-3
读书笔记第三篇。 -
Effective-Objective-C-读书笔记-Item-4-如何正确定义常量
重点是常量定义方式,也是实际项目里很常见的问题。 -
Enum-枚举的正确使用-Effective-Objective-C-读书笔记-Item-5
整理枚举的正确使用方式,包括位掩码等内容。 -
翻译-为什么objc_msgSend必须用汇编实现
这篇同时也属于 Runtime 主题,放在这里是因为它本身是翻译文章。
服务端、跨端与其它:零散但真实的尝试
虽然博客大部分是 iOS,但也有几篇不是纯 iOS 的内容。
这些内容现在看起来更像边界探索:做 iOS 的同时,也会碰到服务端接口、Android 控件、跨语言 RPC 这些问题。写得不一定系统,但代表了当时遇到什么就学什么、学完顺手记录一下的状态。
-
RPC框架Thrift例子-PHP调用C++后端程序
用一个小例子记录 Thrift、PHP、C++ 后端之间的调用。 -
API返回结果设计经验与总结
从接口返回结构出发,讨论code、message、data等字段的设计。 -
Android开源库-LinkTextView-原创
Android 控件文章,也算是早期跨端尝试的一部分。 -
第一篇Blog
真正意义上的第一篇,更多是一个开始的记录。
按年份索引:保留当时的时间线
如果不按主题,而是按时间看,脉络会更明显一些。
2014
2015
- iOS项目的目录结构-原创
- Effective-Objective-C-读书笔记-Item-1
- Effective-Objective-C-读书笔记-Item-2
- Effective-Objective-C-读书笔记-Item-3
- 利用NSProxy实现消息转发-模块化的网络接口层设计-原创
- NSString的Copy与内存分配
- 提升UITableView性能-复杂页面的优化
- Block类型变量-缓存Http请求与回调
- 一次审核被拒的经历-关于iCloud到底应该备份什么数据
- Entity和Model的不同-关于代码的数据层
- UITextView编辑时插入自定义表情-简单的图文混编
- Effective-Objective-C-读书笔记-Item-4-如何正确定义常量
- 有关宏定义的经验与技巧-简化代码-增强Log
- @autoreleasepool-内存的分配与释放
- Enum-枚举的正确使用-Effective-Objective-C-读书笔记-Item-5
- 为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权
- GCD使用经验与技巧浅谈
- RPC框架Thrift例子-PHP调用C++后端程序
- UITextView编辑时插入自定义表情-续-自定义表情图片的大小
- 有趣的Autolayout示例-Masonry实现
- 用Runtime的手段填充任意NSObject对象的nil属性
- 解决iOS项目的版本兼容问题-结合宏、Category和Runtime
- 有趣的Autolayout示例2-Masonry实现
- Swift写的库-TTGSnackbar
- Swift开源项目: TTGEmojiRate的实现
- 有趣的Autolayout示例3-Masonry实现
- 开源项目-TTGTagCollectionView
2016
- 对组件化与模块化的思考与总结
- 总结一些iOS项目中组织代码的方法
- 结合访问Out Parameters出现EXC_BAD_ACCESS的例子,反编译汇编解读__autoreleasing
- API返回结果设计经验与总结
- 翻译-为什么objc_msgSend必须用汇编实现
- 有趣的Autolayout示例4-Masonry实现
- Swift开源Mac App - BingWallPaper
- 开源项目-拼图验证控件TTGPuzzleVerify的实现
2017
- 用QuartzCode快速实现一个收藏动画
- 在对象dealloc的后期执行Task-开源库TTGDeallocTaskHelper
- 有趣的Autolayout示例5-Masonry实现
- 反编译分析Xcode8的Bug, release下连续两次调用有二级指针参数的空方法会Crash
- 反编译分析并模拟实现methodSignatureForSelector方法
总结
这次整理之后再看,过去这些文章其实大致围绕几个关键词:工程结构、Objective-C 底层、UI 实现、性能优化、开源封装。不过更重要的一点是,它们不是一组成熟体系化的技术方案,而是一段学习过程的切片。
单篇文章写的时候往往只是解决一个具体问题,但放在一起看,就能看到当时学习和做项目的路径:先解决页面和业务问题,再关注代码组织和模块拆分,最后慢慢深入到 Runtime、内存管理和反编译验证。
有些文章今天再看会觉得“不够好”:概念解释不够严谨,代码封装不够现代,工程判断也不够成熟。但这其实也是旧文章的意义。它们记录了一个阶段的理解边界,也提醒我技术写作不是一次性写出标准答案,而是在不断实践、验证和回头修正中慢慢变清楚。
隔了 9 年再重新开始写博客,感觉像是把一个很久没打开的项目重新拉起来。代码可以重新编译,文章也可以继续更新。AI 工具会让整理和表达的成本更低,但真正值得记录的,还是项目里遇到的问题、做判断时的取舍,以及过一段时间后依然能回头看的经验。
后面新的文章也会沿着这个索引继续补充。这样博客就不只是按时间堆在一起,而是能变成一份可以回头查、也可以顺着阅读的技术笔记了。