戴铭(iOS开发课)读书笔记:10章节-项目瘦身

原文链接:包大小:如何从资源和代码层面实现全方位瘦身?


前言

关于项目瘦身的相关知识,总体分为三个大类:

  • 官方 App Thinning
  • 图片资源优化
  • 代码瘦身

一般我们接触的项目规模,只要按照规范的开发流程,定期review代码,是不太会涉及到项目瘦身的相关工作的。但是有些知识是我们必须要了解和掌握的。比如:

1 App Store 规定了安装包大小超过 150M 就不能使用蜂窝网络下载,一定要Wi-Fi环境才能下载。(之前这个规定是100M以内,所以微信的大小很长一段时间控制在99M,就是为了能够让用户可以使用蜂窝网络更新)

2 官方规定 App 的 Mach-O 可执行文件有大小限制,不复合规定的无法提交 App Store。

3 一个项目打包成 IPA ,其大小主要是由资源文件及代码组成,其中 Xcode 在打包和上传过程中本身就会对 IPA 做大小优化处理(官方 App Thinning),但是对于图片资源的压缩幅度很小。

下面展开讲讲图片资源和无用代码的优化方法,由于我没有在项目中切实执行过,所以仅当了解。

正文
一、官方 App Thinning

App Thinning 是苹果官方推出的一项改善 App 下载进程的技术,你可能第一次听到这个名字,但是在项目中我们基本都有使用。因为在操作上,它的大部分工作都是由 Xcode 和 App Store 默认完成的。

那它具体做了什么呢?

我们都知道,为了适配不同的设备和屏幕尺寸,我们的 App 需要包含多种芯片架构版本(32位、64位)和不同的分辨率图片资源(2x、3x)。这么多资源都集中在一个包中,势必会增大体积。

App Thinning 的作用就是将众多版本的文件及资源进行切分,用户下载时只会下载一个适合自己设备的版本。
除此之外,如果是游戏类的 App,它可以通过游戏关卡的进度控制资源的下载和删除,这样也可以控制初装 App 的包大小。
当然,它也会通过 Bitcode 针对特定的设备进行包大小优化,只是优化不明显。

我们只需要通过 Xcode 添加和管理 Assets.xcassets 文件即可,其他都不需要我们操作。

二、图片资源优化

之前也提到过,Xcode 打包的过程对图片资源的压缩是很有限的。(例如:我们在项目中使用了总大小为10M的图片资源,最终打包成 IPA 文件时,包含的图片资源总大小依然是 10M 左右)。所以对于图片资源优化空间的效果是立竿见影的,也是比较容易的。

对于图片资源的优化主要体现在 无用图片删除图片资源压缩 这两方面:

1 无用图片删除

原文中介绍了两种方式,一种是获取项目中所有资源文件,通过正则筛选图片资源,过滤使用到的资源文件,取差集。另一种是使用开源工具 LSUnusedResources

1.1 自己写工具
具体步骤如下图所示,我认为难点在于如何取到代码中使用到的资源文件。这个过程我没有想到应该如何实现,如果大家有什么好办法可以私信给我^ ^。


1.2 使用开源工具
LSUnusedResources

2 图片资源压缩

处理完无用的图片资源后,我们还可以对正在使用的图片资源进行压缩来节省空间。

推荐的方式是将图片资源转成WebP。

2.1 图片转 WebP
转换需要借助工具,谷歌开源的 cwebp 或者 腾讯开发的 iSqarta。
工具1: cwebp
工具2: iSqarta
支持从png转webp,其他格式的图片需要先转成png再通过上述工具转成webp

2.2 使用 WebP
WebP-iOS-example

2.3 注意
WebP 在 CPU 性能和解码时间上比 PNG 高两倍,性能和体积的取舍。

2.4 建议
如果图片大小超过100kb时可以考虑使用webp。小雨100kb时,直接使用网页工具TinyPng或者下载工具ImageOptim进行图片压缩。这两个工具的压缩率没有 WebP 那么高,但不会改变图片的压缩方式,所以解析时对性能损耗也不会增加。

三、代码瘦身

可执行文件(Mach-O)的瘦身,就是找到并删除无用代码的过程

1 LinkMap 结合 Mach-O 找无用代码

1 找出方法和类的全集
2 找到使用过的方法和类
3 取二者的差集,就是无用代码
4 无用代码确认后进行删除

1.1 通过分析 LinkMap 来获得所有的代码类和方法的信息

获取 LinkMap 可以通过将 Build Setting 里的 Write Link Map File 设置为 YES,然后指定 Path to Link Map File 的路径即可。(如下图)

LinkMap 文件分为三部分: Object File、Section 和 Symbols。
Object File 包含了代码工程的所有文件
Section 描述了代码段在生成 Mach-O 里的偏移位置和大小
Symbols 会列出每个方法、类、block,以及它们的大小

1.2 通过 Mach-O 获取使用过的方法和类

我们都知道 iOS 中方法的调用都会通过 objc_msgSend 来调用。而 objc_msgSend 在 Mach-O 文件中是通过 __objc_selrefs 这个 section 来获取 selector 参数的。所以 __objc_selrefs 中的 sel 是一定被调用过的方法。__objc_classrefs 中的 class 和 __objc_superrefs 中的 super 是一定被使用过的类。

Mach-O 文件的 __objc_selrefs、_objc_classrefs 和 _objc_superrefs 可以使用 MachOView 这个软件查看。

注意:这个方法的问题在于,Objective-C 是门动态语言,方法调用可以写成运行时动态调用,这样就无法收集全所有调用的方法和类。所以,这种方法找出的无用方法和类只能作为参考。

2 通过 AppCode 找出无用代码

如果工程量不是很大的话,可以直接使用 AppCode 来做分析。

方法: Code -> Inspect Code 静态分析


分析完成后,Unused code 里看到所有无用代码:

当然,使用 AppCode 静态分析出的无用代码也需要审查和处理,需要注意的问题很多,需要我们多次确认后才能删除。

3: 运行时检查类是否真正被使用过

通过 ObjC 的 runtime 源码,我们可以找到怎么判断类是否被初始化:

#define RW_INITIALIZED (1<<29)
bool isInitialized() {
   return getMeta()->data()->flags & RW_INITIALIZED;
}

isInitialized 的结果会保存到元类的 class_rw_t 结构体的 flags 的 1<< 29 位 信息里。

// 类的方法列表已修复
#define RW_METHODIZED         (1<<30)
// 类已经初始化了
#define RW_INITIALIZED        (1<<29)
// 类在初始化过程中
#define RW_INITIALIZING       (1<<28)
// class_rw_t->ro 是 class_ro_t 的堆副本
#define RW_COPIED_RO          (1<<27)
// 类分配了内存,但没有注册
#define RW_CONSTRUCTING       (1<<26)
// 类分配了内存也注册了
#define RW_CONSTRUCTED        (1<<25)
// GC:class 有不安全的 finalize 方法
#define RW_FINALIZE_ON_MAIN_THREAD (1<<24)
// 类的 +load 被调用了
#define RW_LOADED             (1<<23)

不得不说,flags 采用这种位方式记录信息的方式非常巧妙。这么多布尔类型统一管理,方便扩展和检索。值得我们多学习。

既然能够在运行中看到类是否被初始化,那么就能够找出那些类是没有初始化的,进而找到在真实环境中没有用到的类,并清理掉。

最后

对于戴铭老师留的问题:为什么苹果公司要设计元类?
这个问题真的很开放,开放到不知道从哪个角度去回答,千丝万缕又不知道从何讲起。感觉说来说去也只是把元类的作用贯穿一下。
如果大家有什么好的回答思路,可以一起讨论一下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容