The Weekend Blog

I hope it will continue to be updated

LinkMap

前言

苹果对于提交审核的App中可执行文件有明确的大小限制,查看应用的可执行文件大小就需要利用LinkMap文件。

1.如何生成LinkMap文件

1).在工程的Build Setting中找到Write Link Map File并打开开关

2).在debug或者release下编译工程

3).先找到编译后的app文件,向上两级的Products同目录下有Intermediates.noindex文件夹,在该文件夹下能够找到名称为项目名-LinkMap-normal-x86_64.txt的文件(x86_64是架构,如果是真机,可能为arm64或者其他)

2.LinkMap有什么作用

LinKMap文件分为四个部分:

1:# Path:当前LinkMap编译的路径

1
# Path: /Users/zhoumo1/Library/Developer/Xcode/DerivedData/LinkMapTest-brvtnqhfmtphzohebrymhqgdzhwp/Build/Products/Debug-iphonesimulator/LinkMapTest.app/LinkMapTest

2:# Arch:当前编译的系统架构

1
# Arch: x86_64

3:# Object files:编译的所有文件

1
2
3
4
5
6
7
8
9
# Object files:
[  0] linker synthesized
[  1] /Users/zhoumo1/Library/Developer/Xcode/DerivedData/LinkMapTest-brvtnqhfmtphzohebrymhqgdzhwp/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/LinkMapTest.app.xcent
[  2] /Users/zhoumo1/Library/Developer/Xcode/DerivedData/LinkMapTest-brvtnqhfmtphzohebrymhqgdzhwp/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/Objects-normal/x86_64/ViewController.o
[  3] /Users/zhoumo1/Library/Developer/Xcode/DerivedData/LinkMapTest-brvtnqhfmtphzohebrymhqgdzhwp/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/Objects-normal/x86_64/main.o
[  4] /Users/zhoumo1/Library/Developer/Xcode/DerivedData/LinkMapTest-brvtnqhfmtphzohebrymhqgdzhwp/Build/Intermediates.noindex/LinkMapTest.build/Debug-iphonesimulator/LinkMapTest.build/Objects-normal/x86_64/AppDelegate.o
[  5] /Users/zhoumo1/Downloads/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.2.sdk/System/Library/Frameworks//Foundation.framework/Foundation.tbd
[  6] /Users/zhoumo1/Downloads/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.2.sdk/usr/lib/libobjc.tbd
[  7] /Users/zhoumo1/Downloads/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.2.sdk/System/Library/Frameworks//UIKit.framework/UIKit.tbd

4:# Sections:

段表标题中列举出了地址,大小,段类型以及段名称。
数据类型分为两种不同类型,一种是TEXT,用于保存程序代码段经过编译后的机器码,另外一种是DATA用于保存诸如全局变量或者局部变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Sections:
# Address Size        Segment Section
0x100001590   0x00000453  __TEXT  __text
0x1000019E4   0x00000036  __TEXT  __stubs
0x100001A1C   0x0000006A  __TEXT  __stub_helper
0x100001A86   0x00000A70  __TEXT  __objc_methname
0x1000024F6   0x0000003C  __TEXT  __objc_classname
0x100002532   0x00000878  __TEXT  __objc_methtype
0x100002DAA   0x0000007A  __TEXT  __cstring
0x100002E24   0x00000186  __TEXT  __entitlements
0x100002FAC   0x00000048  __TEXT  __unwind_info
0x100003000   0x00000010  __DATA  __nl_symbol_ptr
0x100003010   0x00000048  __DATA  __la_symbol_ptr
0x100003058   0x00000010  __DATA  __objc_classlist
0x100003068   0x00000010  __DATA  __objc_protolist
0x100003078   0x00000008  __DATA  __objc_imageinfo
0x100003080   0x00000C48  __DATA  __objc_const
0x100003CC8   0x00000030  __DATA  __objc_selrefs
0x100003CF8   0x00000008  __DATA  __objc_classrefs
0x100003D00   0x00000008  __DATA  __objc_superrefs
0x100003D08   0x00000008  __DATA  __objc_ivar
0x100003D10   0x000000A0  __DATA  __objc_data
0x100003DB0   0x000000C0  __DATA  __data

5:# Symbols:文件中每一个方法的大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Symbols:
# Address Size        File  Name
0x100001590   0x00000040  [  2] -[ViewController viewDidLoad]
0x1000015D0   0x00000050  [  2] -[ViewController viewDidAppear:]
0x100001620   0x00000050  [  2] -[ViewController viewWillAppear:]
0x100001670   0x00000050  [  2] -[ViewController viewDidDisappear:]
0x1000016C0   0x0000003C  [  2] -[ViewController didReceiveMemoryWarning]
0x100001700   0x00000090  [  3] _main
0x100001790   0x00000080  [  4] -[AppDelegate application:didFinishLaunchingWithOptions:]
0x100001810   0x00000040  [  4] -[AppDelegate applicationWillResignActive:]
0x100001850   0x00000040  [  4] -[AppDelegate applicationDidEnterBackground:]
0x100001890   0x00000040  [  4] -[AppDelegate applicationWillEnterForeground:]
0x1000018D0   0x00000040  [  4] -[AppDelegate applicationDidBecomeActive:]
0x100001910   0x00000040  [  4] -[AppDelegate applicationWillTerminate:]
0x100001950   0x00000020  [  4] -[AppDelegate window]
0x100001970   0x00000040  [  4] -[AppDelegate setWindow:]
0x1000019B0   0x00000033  [  4] -[AppDelegate .cxx_destruct]
···

3.如何减少库大小

除了第三方的库以外,我们还能对自己的代码做些什么?

1)注释或删除空方法和没有调用的方法

如上文分析,类中存在的方法就会被计算大小,无论是否调用。所以可以删除类中 如:

1
2
3
4
5
6
- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
}
- (void)viewDidDisappear:(BOOL)animated{
    [super viewDidDisappear:animated];
}

多加了两个空方法的大小对比如下,虽然空方法占用的很少,但是如果数量比较多还是很可观。

2)比较去重

分析过滤项目中的重复代码。通过整合减少代码量。

介绍一种去重的方法,使用PMD去重:
1.下载:https://sourceforge.net/projects/pmd/files/pmd/
2.cd 到bin目录中
3.在终端输入

1
./run.sh cpd --language ObjectiveC --minimum-tokens 100 --files /Users/zhoumo1/Desktop/LinkMap/LinkMapTest/LinkMapTest > /Users/zhoumo1/Desktop/check.txt 

4.查看结果~完美

3)升级最低版本||重构

这没什么好说的,iOS9已经支持到500M,如果实在不能删减,升级最低支持版本是最有效的。

重构风险较大,并且重构后也不一定会小很多,不支持。

4.LinkMap比对

为了方便查看做了以上减少工作后的结果如何,于是写了一个简单的Mac应用,主要功能是对比两份LinkMap文件。

git地址:https://github.com/zhoumo199163/compareLinkMap

如果觉得对你有用,欢迎star~