Texture源码导读

TODO: 待补充

May 2, 2026

启动优化

iOS应用的启动时间是用户体验的关键指标之一。研究表明,应用性能直接影响用户留存:页面加载时间每增加1秒,用户流失率会显著上升。对于iOS应用,需要在20秒内完成启动,否则可能会被watchdog强制终止。 本系列文章从启动流程的各个阶段入手,系统性地介绍iOS启动优化的方法和实践。 启动监控是 APM 的重要子系,线上 P50/P90/P99 的采集、冷/温/热启动判定、以及与业务秒开指标的关联,请参考 APM 系列:指标体系、数据采集。 启动流程概述 App的启动流程分为两个主要阶段: 阶段 时间范围 主要工作 Pre-main 进程创建 → main()函数 加载可执行文件、加载动态库、Rebase/Bind、ObjC Runtime初始化、Swift Runtime元数据注册、+load方法、Initializers main main()函数 → 首帧渲染 UIApplicationMain、AppDelegate回调、首帧渲染 flowchart TD Start([App 冷启动]) --> PreMain subgraph PreMain["Pre-main 阶段"] direction TB A[加载可执行文件创建进程、mmap映射、签名验证] --> B[加载动态库递归加载依赖、包括 Swift Runtime] B --> C[Rebase & Bind指针修正、符号绑定] C --> D[ObjC Runtime 初始化类注册、Category 附加] D --> E[Swift Runtime 元数据注册类型元数据、协议遵循表] E --> F[调用 +load 方法] F --> G[执行 InitializersC++静态构造函数、__attribute__] end PreMain --> MainPhase subgraph MainPhase["main 阶段"] direction TB H[main函数] --> I[UIApplicationMain创建UIApplication、AppDelegate、启动RunLoop] I --> J[AppDelegate回调willFinish、didFinishLaunching] J --> K[首帧渲染创建Window、RootViewController、首屏UI] end MainPhase --> End([启动完成]) 文章导航 本系列包含以下文章,建议按顺序阅读: ...

May 2, 2026

插件化架构详解

什么是插件化 在iOS开发中,插件化通常指的是编译期插件化,即通过壳工程(Shell Project)按需装配不同的业务组件,生成不同功能的App。这与Android的运行时插件化(动态加载代码)有本质区别。 iOS插件化 vs Android插件化 特性 Android插件化 iOS插件化 实现方式 运行时动态加载APK/DEX 编译期按需集成组件 代码热更新 支持 不支持(App Store限制) 主要目的 绕过包大小限制、热修复 多App复用、编译提效 技术难度 高(Hook系统API) 中(工程配置) iOS的"插件化"主要体现在: 壳工程设计:一套代码支撑多个App 配置驱动集成:通过配置文件决定集成哪些组件 二进制化提效:稳定组件编译为二进制,减少编译时间 flowchart TB subgraph 组件库["组件仓库"] A[用户组件] B[商城组件] C[直播组件] D[社区组件] E[基础组件] end subgraph 壳工程["壳工程 (Shell Project)"] Config["配置文件"] Shell["壳工程代码"] end subgraph Apps["生成的App"] App1["App A(用户+商城+基础)"] App2["App B(用户+直播+基础)"] App3["App C(全量组件)"] end A & B & C & D & E --> Config Config -->|"按需装配"| App1 Config -->|"按需装配"| App2 Config -->|"按需装配"| App3 两种插件化实现方式 根据组件间通信方案的不同,iOS插件化有两种主要实现方式,它们的核心区别在于是否强制要求编译期隔离: ...

May 2, 2026

编译优化-观测

“无法度量就无法优化”。在开始任何编译优化动作之前,必须先建立一套可重复、可对比的观测手段,否则改动的真实收益无从谈起。本文介绍 iOS 编译耗时观测的主要工具链和原理。 观测目标分层 不同层次的观测工具回答不同的问题: flowchart TD A[编译耗时观测] --> B[整体耗时] A --> C[阶段耗时] A --> D[任务级耗时] A --> E[函数/表达式级] B --> B1[xcodebuild 总耗时] C --> C1[Build Timing Summary] C --> C2[Pod Install 阶段计时] D --> D1[Build Timeline] D --> D2[XCLogParser] E --> E1[-debug-time-compilation] E --> E2[-warn-long-expression] 观测层次 典型问题 工具 整体 一次构建花了多久? time xcodebuild、MetricKit 阶段 哪个阶段最慢? -showBuildTimingSummary、Build Timing Summary 任务 哪个文件/目标最慢? Xcode Build Timeline、XCLogParser 函数级 哪个函数/表达式让前端卡住? -debug-time-function-bodies、-warn-long-expression-type-checking 整体耗时 xcodebuild 命令行计时 最简单也最稳定的方式是直接给 xcodebuild 加 time: ...

May 5, 2026

fishhook 源码导读

fishhook 由 Facebook 于 2013 年开源,用于在运行时动态重绑定(rebind)Mach-O 中被 dyld 绑定的 C 符号,是 iOS/macOS 逆向与底层埋点(malloc 追踪、双 close 检测、网络 socket 拦截、NSLog 重定向等)领域的"瑞士军刀"。 一、fishhook 是什么 一句话定义:fishhook 通过修改 Mach-O 镜像中 __DATA(_CONST) 段里 __la_symbol_ptr / __nl_symbol_ptr 两个 Section 中的函数指针,把对外部 C 符号(如 open、close、NSLog)的调用重定向到自定义的替换函数,同时保留原函数指针供回调使用。 它提供的能力类似 macOS 上 DYLD_INTERPOSE 宏(编译期 interpose),但: 运行时生效:不需要重新编译依赖库,随时可以在 App 启动后对系统库的 C 函数下钩子; 支持动态加载的 image:注册后对后续 dlopen 加载的 image 同样生效; 对业务零侵入:不改 App 本身的代码段,也不破坏符号表,只是重写 GOT/stub 里的一个指针。 但它也有非常明确的能力边界: 能力 是否支持 Hook 通过 dyld 动态绑定的外部 C 函数(libSystem、CoreFoundation 里的 C API、objc_msgSend 等) 是 Hook Objective-C 方法(-[NSString length]) 否(要用 Method Swizzling) Hook 当前 image 内部的 C 函数(静态链接、static、内联) 否(它不走 __la_symbol_ptr,直接是段内相对寻址) Hook Swift 方法(除非显式 @_cdecl) 否 Hook 已经解析并内联到寄存器里的符号(如 LTO 后消失的符号) 否 记住这条原则:fishhook 的作用域 = 被 dyld 绑定为"间接符号"(Indirect Symbol)的 C 符号。 ...

May 2, 2026

SIL(Swift Intermediate Language)

SIL(Swift Intermediate Language,Swift 中间语言)是 Swift 编译器在编译过程中生成的一种中间表示(Intermediate Representation,IR)。它位于 Swift 源码与 LLVM IR 之间,是 Swift 编译器架构中至关重要的一层。 SIL 的设计目标是: 对 Swift 语言的高级语义进行精确建模 在高层抽象的基础上执行强大的优化 保留足够的类型信息,用于诊断和安全检查 作为 Swift 特有优化的载体,弥补 LLVM IR 无法直接表达 Swift 语义的不足 SIL 并不是给开发者日常编写的语言,而是编译器的内部表示。理解它有助于深入理解 Swift 的编译过程、性能优化原理和内存管理机制。 Swift 编译流程概览 在了解 SIL 之前,需要先理解 Swift 的整体编译流程: flowchart TD A[Swift 源代码 .swift] --> B[词法分析 Lexer] B --> C[语法分析 Parser] C --> D[语义分析 Sema] D --> E[SILGen: 生成 Raw SIL] E --> F[SIL 优化 Guaranteed Passes] F --> G[SIL 优化 General Passes] G --> H[IRGen: 生成 LLVM IR] H --> I[LLVM 优化] I --> J[机器码 .o] J --> K[链接器 Linker] K --> L[可执行文件 / 动态库] 各阶段简述 词法分析(Lexer) 编译的第一步。Lexer 逐字符扫描 .swift 源文件,将其切分为一系列Token(词法单元),例如关键字 func、标识符 add、运算符 +、字面量 42、左右括号等。Token 是后续所有分析的最小输入单位。这一步会剥离注释和空白,但保留它们的位置信息以便后续生成精确的诊断信息(错误提示的行号和列号)。 ...

May 2, 2026

组件化架构详解

什么是组件化 组件化是一种工程架构思想,将一个大型App拆分为多个独立的业务组件(Module),每个组件可以独立开发、独立测试、独立编译,组件之间通过中间层进行解耦通信。 组件化解决的问题 问题 未组件化 组件化后 编译速度 全量编译,耗时长 只编译修改的组件,支持二进制化 团队协作 代码冲突频繁 独立仓库,减少冲突 代码复用 复制粘贴,难以维护 组件复用,统一维护 耦合度 类之间直接依赖,牵一发动全身 通过中间层通信,解耦 测试 难以单元测试 组件可独立测试 组件化与页面架构的关系 组件化是工程架构,关注的是App整体的模块划分和通信方式;而MVC、MVVM、TCA等是页面架构,关注的是单个页面内的代码组织。 两者并不冲突,在大型项目中通常会同时采用: 工程层面:使用组件化拆分业务模块 组件内部:每个组件使用MVVM/TCA等页面架构 flowchart TB subgraph App["App壳工程"] subgraph Module1["首页组件"] M1V["View"] M1VM["ViewModel"] M1M["Model"] end subgraph Module2["商城组件"] M2V["View"] M2VM["ViewModel"] M2M["Model"] end Router["路由/中间件"] end Module1 <--> Router Module2 <--> Router 组件化的分层架构 典型的组件化架构采用三层结构: flowchart TB subgraph 业务层["业务层 - Business Layer"] A[首页组件] B[商城组件] C[用户组件] D[消息组件] end subgraph 中间层["中间层 - Mediator Layer"] E[路由Router] F[服务Service] end subgraph 基础层["基础层 - Foundation Layer"] G[网络库] H[图片库] I[数据库] J[工具库] end A & B & C & D --> E & F E & F --> G & H & I & J 业务层(Business Layer) 业务层包含各个业务组件,每个组件是一个独立的业务单元: ...

May 2, 2026

耗电-CPU与后台优化

CPU是App最容易"无意识"耗电的模块,而后台则是最容易"偷偷"耗电的场景。本文聚焦这两大问题域,给出具体的优化手段。 一、CPU耗电的根本原因 根据 耗电-原理 中的分析,CPU耗电由三部分构成: 活跃时间:CPU处于C0/P0的时间。 瞬时功率:和P-State频率相关。 唤醒次数:频繁从C-State唤醒无法进入深度休眠。 对应三条优化方向: 优化方向 策略 减少活跃 任务及时结束,该停就停 降低功率 避免无谓的满核满频,使用合适的QoS 合并唤醒 聚合Timer、聚合任务,让CPU能连续工作后进入深休眠 二、识别CPU耗电热点 从MetricKit入手 cumulativeCPUTime 是线上最直接的CPU指标。对比同版本前后、同机型前后的CPU时长,能快速定位回归。 Time Profiler的使用技巧 在Instruments中抓一份Time Profiler Trace后: 按"Heavy Stack"视图查看耗时函数。 关注后台的采样(通过Xcode的生命周期切换复现)。 查看线程调用频率——单次耗时低但高频调用的函数,同样是耗电大头。 代码层面的CPU异味 // 1. 死循环轮询 while isWaitingForData { if dataReady { break } } // 2. 主线程sleep循环 DispatchQueue.global().async { while true { checkStatus() Thread.sleep(forTimeInterval: 0.1) } } // 3. 密集Timer Timer.scheduledTimer(withTimeInterval: 0.016, repeats: true) { _ in self.updateUI() } // 4. 无限制的CADisplayLink displayLink = CADisplayLink(target: self, selector: #selector(tick)) displayLink.add(to: .main, forMode: .common) // 页面隐藏后忘记invalidate 这些代码在Time Profiler中都会显示出异常高的调用频率。 ...

May 2, 2026

CocoaPods 源码导读:从下载到工程集成

本文是系列第三篇,基于 CocoaPods 1.16.2 源码。上一篇我们停在 Analyzer 产出 AnalysisResult,本文继续走完 download_dependencies → validate_targets → generate_pods_project → integrate_user_project → write_lockfiles 这五个阶段。 上一篇:从命令到依赖求解 · 首篇:架构总览 一、全景:从 spec 到可编译的工程 先把本文要走的流程重新放一遍,让你带着地图读代码: flowchart TB A[AnalysisResult] --> B[download_dependencies] B -->|per pod| B1[PodSourceDownloader] B1 -->|命中| C1[Downloader::Cache] B1 -->|未命中| C2[cocoapods-downloaderGit/HTTP/SVN/...] C2 --> C3[rsync → Pods/<name>/] B -->|per pod| B2[PodSourceInstaller] B2 --> B3[PodSourcePreparerprepare_command] B2 --> B4[PodDirCleaner按 spec.source_files 裁剪] B --> D[validate_targetsTargetValidator#validate!] D --> E[generate_pods_project] E --> E1[ProjectCacheAnalyzer增量识别要重生成的 target] E --> E2[SinglePodsProjectGenerator#generate!] E2 --> E21[FileReferencesInstaller] E2 --> E22[PodTargetInstaller] E2 --> E23[AggregateTargetInstaller] E2 --> E24[xcconfig / modulemap / umbrella / info.plist / dummy.m] E --> E3[PodsProjectWriter#write!写盘前触发 Podfile post_install] E --> F[integrate_user_project] F --> F1[create_workspace写 .xcworkspace] F --> F2[deintegrate_removed_targets] F --> F3[TargetIntegrator#integrate!xcconfig / frameworks / scripts] F --> G[write_lockfiles] G --> G1[Podfile.lock] G --> G2[Pods/Manifest.lock] G --> H[perform_post_install_actionsplugin post_install hook] 对应的 Installer#install! 片段: ...

May 2, 2026

Swift中import详解

源码版本说明:本文涉及的源码基于 Swift 编译器 开发版本(swift main分支,commit: e0db5152d4d4,2026-01-19)。不同版本的实现细节可能略有差异,但核心机制保持一致。 在前一篇文章Objective-C中import详解中,我们深入探讨了 Objective-C 中的 import 机制,包括 #include、#import、@import 以及 Clang Modules 的工作原理。本文将继续从 Swift 编译器的角度,讲解 Swift 中 import 的语法、模块查找机制、底层实现原理以及与 Objective-C 的互操作。 从 Clang Module 到 Swift Module 在深入 Swift 的 import 机制之前,让我们先回顾一下上一篇文章中 Clang Module 的核心概念。 Clang Module 核心概念回顾 在 Objective-C 文章中,我们学习了 Clang Module 的几个关键特性: module.modulemap:定义模块结构的配置文件 framework module Foundation { umbrella header "Foundation.h" export * } 预编译模块缓存(.pcm 文件):Clang 将模块编译为二进制格式,缓存以加速后续编译 懒加载机制:只加载实际使用的声明,未使用的部分不会被解析 自动链接:@import 会自动链接对应的库,无需手动配置 模块查找路径:通过 -I、-F 等参数指定搜索路径 Swift 如何继承 Clang Module 的设计 Swift 的模块系统并非从零开始设计,而是站在 Clang Module 的肩膀上,继承了其核心优势,并针对 Swift 的特性进行了扩展: ...

May 2, 2026