2019.12.04
ASR service 增加 enable remote silence。
2019.12.06
present 同一个VC会crash。
UI操作要放到主线程。
2019.12.09
iOS 启动优化
启动过程
冷启动:不在内存,也不存在进程。
热启动:APP结束后再启动,有部分在内存但没有进程存在。
resume:APP没结束,全在内存内存中,进程也存在。
iOS启动过程:
• 根据 info.plist 里的设置加载闪屏,建立沙箱,对权限进行检查等;
• 加载 Mach-O;
• 执行 attribute 的 constructor 函数;
• 加载类扩展;
• 加载 C++静态对象;
• 调用+load 函数;
• 执行 main 函数;
• Application 初始化,到 applicationDidFinishLaunchingWithOptions 执行完;
• 初始化帧渲染,到 viewDidAppear 执行完,用户可见可操作。
分析工具
Instruments,App launch。
分析纬度
线程是计算机资源调度和分配的基本单位,CPU 的使用情况会体现到线程上。
主线程耗时:
1、使用 Messier 生成 trace json 进行分析。
2、手动 hook objc_msgSend 生成 Objective-C 方法耗时数据分析。GCDFetchFeed/SMCallTraceCore.c at master · ming1016/GCDFetchFeed · GitHub
CPU:
1、使用 Energy Log 检查 CPU 耗电,前台三分钟或者后台一分钟 CPU 线程连续占用80%以上判定为耗电,同事记录耗电线程堆栈供分析。
2、查看线程情况,task_theads 的 act_list 数组包含所有线程,使用 thread_info 的接口可以返回线程的基本信息 thread_basic_info_t。
内存:
1、查看 APP 内存真实使用情况,webkit/MemoryFootprintCocoa.cpp。
2、JetSam 会判断 APP 内存使用情况,超出阈值就会杀死APP。
3、NSProcessInfo 的 physicalMemory 表示设备物理内存大小。
网络:
1、使用 Fishhook hook 网络底层库 CFNetwork。
2、指标:DNS 时间,SSL 时间,首包时间,响应时间。
I/O:
1、使用 Frida,动态二进制插桩技术,在程序运行时区插入自定义代码获取 I/O 的耗时和处理数据大小等数据。
2、WWDC。
延后任务管理
对于分析后,没必要在启动阶段执行的方法,可以延后执行。一般创建四个队列:
• 异步串行队列:执行有依赖关系的任务。
• 异步并行队列:分组执行独立任务,限制任务数量,避免CPU和内存瞬时激增影响主线程用户操作。
• 闲时主线程串行队列:监听主线程 runloop 状态,在 kCFRunLoopBeforeWaiting 时开始执行闲时队列里的任务,在 kCFRunLoopAfterWaiting 是停止。
• 闲时异步串行队列:同上。
优化后如何保持
监控启动阶段方法耗时,出现异常快速定位。
通过 JSON 表示监控数据,自动化分析和定位。
2019.12.10
CLLocationManager 请求权限需要被强引用。
2019.12.19
iOS 项目架构
小团队
MVC
MVP
MVVM
MVCS
大团队
需要考虑如何划分模块粒度、如何分层、如何团队协作。
划分模块粒度
首先,模块划分需要遵循规范、清晰的原则。
其次,SOLID 原则。
- 单一功能原则:对象功能要单一,不要在一个对象里添加很多功能。
- 开闭原则:扩展是开放的,修改是封闭的。
- 里氏替换原则:子类对象是可以替代基类对象的。
- 接口隔离原则:接口的用途要单一,不要在一个接口上根据不同的参数实现多个功能。
- 依赖反转原则:方法应该依赖抽象,不要依赖实例。iOS 开发就是高层业务方法依赖于协议。 最后,选择合适的粒度。iOS 组件,应该是包含 UI 控件,相关多个小功能的合集,是一种粒度适中的模块。
先按物理划分为不同的pod库,然后梳理组件之间的逻辑关系,进行改造。
组件分层:
1. 底层是与业务无关的基础组件,比如网络和存储等;
2. 中间层是通用的业务组件,比如账号、埋点、支付、购物车等;
3. 最上层是迭代业务组件,更新频率最高。
被多个业务或团队使用的功能模块才需要做成组件。
多团队分工
首先,基建团队,负责业务无关的基础功能组件和业务相关的通用业务组件。
然后,业务团队,耦合度高的业务可以划分成单独的业务团队。
最后,人员相互流动,相互了解。
理想的架构
协议式架构:采用协议式编程思路,在编译层使用协议定义规范,实现可在不同地方,从而达到分布管理和维护组件的目的。
缺点:缺少统一调度层,导致难于集中管理;协议过于规范,不够灵活。
中间者架构:采用中间者统一管理的方式,来控制APP的整个生命周期中组件的调用关系。组件接口设计要保持一致。
CTMediator,运行时解耦。
2019.12.31
使用 lame
库,实现 pcm 流 转 mp3 流。