1.1. 删除无用图片
使用开源工具 LSUnusedResources 检查重复图片,但是可能会有误报,比如 [@”image%d”, index] 这种引用方式无法检查到,需要人工在核对一边。
1.1.1重复文件删除
借助 fdupes 这个开源工具,校验各资源的 MD5。
1.2. 图片文件压缩
使用开源工具 imageOptim 对所有图片压缩一遍。此工具会使用 git 上主流的图片压缩方法尝试一遍,选择最优方案。
1.3. 纯色图片使用代码生成
如果项目中纯色的图片比较多,可以考虑使用代码替代,生成后缓存到本地以供后期使用。
1.4. 不常用图片后台下发
对于项目中不常用的图片可以考虑由后台下发,但是此项收益可能不高,而且会影响使用体验,酌情使用。
1.5. 字体文件
字体文件一般都很大,如果项目中使用了多种字体文件,可以删掉不常用的字体文件。
Mach-O 为 Mach Object 文件格式的缩写,它是一种用于可执行文件、目标代码、动态库、内核转储的文件格式。作为 a.out 格式的替代,Mach-O 提供了更强的扩展性,并提升了 符号表 中信息的访问速度。
MachO 是一种文件规范,是一类文件的统称,包括但不限于以下几种常见的文件类型:
Header是文件的头部信息,包括CPU信息、文件类型、Command条数及Size信息。总体来说,作为开发者Header使用的较少,比较常用的是(uintptr_t)&_mh_execute_header获取header地址进行计算用。
Load Commands描述的是文件的加载信息,加载信息有很多,加载的段、符号表、动态库信息等都在Commands中取到。这个部分信息还是比较有用的,我们可以从这里获取到符号表和字符串表的偏移量
Header 区域主要用于存储 MachO 文件的一般信息,并且描述了 LoadCommands 区域 而 LoadCommands 区域则详细描述了 Data 区域 如果说 Header 区域和 LoadCommands 区域的主要作用是:
那么,Data 区域的作用,就是当程序运行起来后,为每一个映射到虚拟内存中的指令操作提供真实的物理存储支持
Data 区域通常是 MachO 文件中最大的部分,主要包含:代码段、数据段,链接信息等 注意:不要把 Data 区域与数据段搞混掉了,Data 区域指的是广义上的数据,而不是特指数据段的数据
Section | 用途 |
---|---|
__TEXT.__text | 主程序代码,存放的是汇编后的代码 |
__TEXT.__cstring | C 语言字符串 |
__TEXT.__const | const 关键字修饰的常量 |
__TEXT.__stubs | 用于 Stub 的占位代码,很多地方称之为桩代码。 |
__TEXT.__stubs_helper | 当 Stub 无法找到真正的符号地址后的最终指向 |
__TEXT.__objc_methname | Objective-C 方法名称 |
__TEXT.__objc_methtype | Objective-C 方法类型 |
__TEXT.__objc_classname | Objective-C 类名称 |
__DATA.__data | 初始化过的可变数据 |
__DATA.__la_symbol_ptr | lazy binding 的指针表,表中的指针一开始都指向 __stub_helper |
__DATA.nl_symbol_ptr | 非 lazy binding 的指针表,每个表项中的指针都指向一个在装载过程中,被动态链机器搜索完成的符号 |
__DATA.__const | 没有初始化过的常量 |
__DATA.__cfstring | 程序中使用的 Core Foundation 字符串(CFStringRefs) |
__DATA.__bss | BSS,存放为初始化的全局变量,即常说的静态内存分配 |
__DATA.__common | 没有初始化过的符号声明 |
__DATA.__objc_classlist | Objective-C 类列表 |
__DATA.__objc_protolist | Objective-C 原型 |
__DATA.__objc_imginfo | Objective-C 镜像信息 |
__DATA.__objc_selfrefs | Objective-C self 引用 |
__DATA.__objc_protorefs | Objective-C 原型引用 |
__DATA.__objc_superrefs | Objective-C 超类引用 |
OTool 是 macOS 自带的 MachO 文件查看工具,基于命令行,可以通过不同的命令参数快速地查看 MachO 文件各个方面的信息,OTool 位于(/Library/Developer/CommandLineTools/usr/bin/otool)
“otool - ov $path”将输出Objective - C类结构及其定义的方法。
通过匹配可以和筛选,可以将获取所有的方法,除了setter and getter方法…
代码
def imp_selectors(path):
re_sel_imp = re.compile('\s*imp\s*0x\w+ ([+|-]\[.+\s(.+)\])')
re_properties_start = re.compile('\s*baseProperties 0x\w{9}')
re_properties_end = re.compile('\w{16} 0x\w{9} _OBJC_CLASS_\$_(.+)')
re_property = re.compile('\s*name\s*0x\w+ (.+)')
imp_sels = {}
is_properties_area = False
for line in os.popen('/usr/bin/otool -oV %s' % path).readlines():
results = re_sel_imp.findall(line)
if results:
(class_sel, sel) = results[0]
if sel in imp_sels:
imp_sels[sel].add(class_sel)
else:
imp_sels[sel] = set([class_sel])
else:
# delete setter and getter methods as ivar assignment will not trigger them
# 删除相关的set方法
if re_properties_start.findall(line):
is_properties_area = True
if re_properties_end.findall(line):
is_properties_area = False
if is_properties_area:
property_result = re_property.findall(line)
if property_result:
property_name = property_result[0]
if property_name and property_name in imp_sels:
# properties layout in mach-o is after func imp
imp_sels.pop(property_name)
# 拼接set方法
setter = 'set' + property_name[0].upper() + property_name[1:] + ':'
# 干掉set方法
if setter in imp_sels:
imp_sels.pop(setter)
return imp_sels
otool -v -s __DATA __objc_selrefs $path
所有代码与引用的代码的差集即为未使用代码