项目大了,就会遇到很多问题, 一个好的项目必然有好的项目架构,保证项目的健壮性和可扩展性,小编现在还没有能力去谈架构,还不具备写那样的文章, 于是,就项目里遇到的几个问题,做一下简单的总结。
关于ipa包的问题,项目大了,自然是想要控制ipa包的大小, 尽量压缩文件的大小,这样做的原因可能是有一部分用户喜欢下载容量较小的应用,具体是不是这样,你可以给与评论回复。
1. 为了减少ipa包的大小,大的项目往往会有很多的图片资源, 而这些图片资源有一部分会因为同一个资源不同的命名而两次或者多次的加到工程里,实际中在项目里也遇到了这个问题,那怎么找到重复的资源呢,直接用眼看, 不错, 这是一个方法, 但是这会事倍功半,于是小编发现了一个比较好的工具 duplicate photo cleaner,这个工具我相信你可以轻松的找见。 工具的用法也很简单: 首先选择你工程里的图片资源路径,然后 startScan,ok,这样分析以后, 你是不是很容易的对比出哪一些图片资源是重复的,是可以删减的了。下面是工具的截图。
这些图片已经优化, 所以重复的都已删掉2.由于工程里的文件众多,每个文件的大小不小, 好多牛逼的人去了一个新公司, 往往牛逼的去选择重构项目, 关于重构项目的一点经验,你可以看这个人写的一篇博客, 个人感觉还不错 http://blog.csdn.net/colorapp/article/details/48597267,工程单个文件太大了,也不太好, 往往需要找出来进行优化一下,昨天领导就给了我这样的一个需求:检查下编译后各文件编译后.o文件大小,要求从大到小排,给前50个就可以。 收到任务后马上进行了开展,首先我们知道一个app编译后,除了图片资源以外,就剩了一个可执行文件. 如果你想查看,可以window-organizer(图一)
然后 show-in-finder(图二)你会找到这个.xcarchive文件, 直接显示包内容就行了,显示包内容后你会看到dsym文件, 关于这个文件,后文会提及到, 还有产品文件,(图三) 现在我们只看生成的产品, 最后生成的产品 显示包内容就行了(图四),结果就是些图片资源还有可执行文件了。
图一 图二 图三 图四现在回到我们的需求上来, 怎么查看可执行文件的结构呢, 还好,Xcode帮我们做了这些事情。
****************************************************************************以下引用网络资源
1.XCode开启编译选项Write Link Map File XCode -> �target -> Build Settings -> 搜map -> 把Write Link Map File选项设为yes,并指定好linkMap的存储位置
图六2.编译后,到编译目录里找到该txt文件,文件名和路径就是上述的Path to Link Map File
路径如图八所示
位于~/Library/Developer/Xcode/DerivedData/XXX-eumsvrzbvgfofvbfsoqokmjprvuh/Build/Intermediates/XXX.build/Debug-iphoneos/XXX.build/
这个LinkMap里展示了整个可执行文件的全貌,列出了编译后的每一个.o目标文件的信息(包括静态链接库.a里的),以及每一个目标文件的代码段,数据段存储详情
XCode -> Project -> Build Settings -> 搜map -> 把Write Link Map File选项设为yes,并指定好linkMap的存储位置
这个文件可以让你了解整个APP编译后的情况,也许从中可以发现一些异常,还可以用这个文件计算静态链接库在项目里占的大小,有时候我们在项目里链了很多第三方库,导致APP体积变大很多,我们想确切知道每个库占用了多大空间,可以给我们优化提供方向。LinkMap里有了每个目标文件每个方法每个数据的占用大小数据,所以只要写个脚本,就可以统计出每个.o最后的大小,属于一个.a静态链接库的.o加起来,就是这个库在APP里占用的空间大小。
****************************************************************************以上引用网络资源
需求基本上得到解决, 在上面build目录怎么寻找, 添加一张网络图片(图七):
图七 图八接着我们我们分析下.linkFileList文件
文件内容很多,你会发现每个方法都有一个文件的偏移位置
在这里截几个图给大家看看
可以看到一个段表,描述各个段在最后编译成的可执行文件中的偏移位置及大小,包括了代码段(__TEXT,保存程序代码段编译后的机器码)和数据段(__DATA,保存变量值)
# Sections:
# Address Size Segment Section
0x00002740 0x00273890 __TEXT __text
0x00275FD0 0x00000ADA __TEXT __symbol_stub
0x00276AAC 0x00001222 __TEXT __stub_helper
0x00277CCE 0x00019D9E __TEXT __objc_methname
0x00291A70 0x00012847 __TEXT __cstring
0x002A42B7 0x00001FC1 __TEXT __objc_classname
0x002A6278 0x000046A7 __TEXT __objc_methtype
0x002AA920 0x000061CE __TEXT __ustring
0x002B0AF0 0x00000764 __TEXT __const
0x002B1254 0x000028B8 __TEXT __gcc_except_tab
0x002B3B0C 0x00004EBC __TEXT __unwind_info
0x002B89C8 0x0003662C __TEXT __eh_frame
0x002EF000 0x00000014 __DATA __program_vars
0x002EF014 0x00000284 __DATA __nl_symbol_ptr
0x002EF298 0x0000073C __DATA __la_symbol_ptr
0x002EF9E0 0x000030A4 __DATA __const
0x002F2A84 0x00000590 __DATA __objc_classlist
0x002F3014 0x0000000C __DATA __objc_nlclslist
0x002F3020 0x0000006C __DATA __objc_catlist
0x002F308C 0x000000D8 __DATA __objc_protolist
0x002F3164 0x00000008 __DATA __objc_imageinfo
0x002F3170 0x0002BC80 __DATA __objc_const
0x0031EDF0 0x00003A30 __DATA __objc_selrefs
0x00322820 0x00000014 __DATA __objc_protorefs
0x00322834 0x000006B8 __DATA __objc_classrefs
0x00322EEC 0x00000394 __DATA __objc_superrefs
0x00323280 0x000037C8 __DATA __objc_data
0x00326A48 0x000096D0 __DATA __cfstring
0x00330118 0x00001424 __DATA __objc_ivar
0x00331540 0x00006080 __DATA __data
0x003375C0 0x0000001C __DATA __common
0x003375E0 0x000018E8 __DATA __bss
首列是数据在文件的偏移位置,第二列是这一段占用大小,第三列是段类型,代码段和数据段,第四列是段名称。
每一行的数据都紧跟在上一行后面,如第二行__symbol_stub的地址0x00275FD0就是第一行__text的地址0×00002740加上大小0×00273890,整个可执行文件大致数据分布就是这样。
这里可以清楚看到各种类型的数据在最终可执行文件里占的比例,例如__text表示编译后的程序执行语句,__data表示已初始化的全局变量和局部静态变量,__bss表示未初始化的全局变量和局部静态变量,__cstring表示代码里的字符串常量,等等。
3
接着就是按上表顺序,列出具体的按每个文件列出每个对应字段的位置和占用空间
# Address Size File Name
0x00002740 0x0000003E [ 1] start
0x00002780 0x00000400 [ 2] +[TKPFileInfo parseWithDictionary:]
0x00002B80 0x00000030 [ 2] -[TKPFileInfo fileID]
...
同样首列是数据在文件的偏移地址,第二列是占用大小,第三列是所属文件序号,对应上述Object files列表,最后是名字。
例如第二行代表了文件序号为2(反查上面就是TKPFileInfo.o)的parseWithDictionary方法占用了1000byte大小。
小小总结:
以上就是linkmap文件的分析,linkmap文件是xcode link时产生的中间文件,一般用于调试,可以精确知道某个地址对应的函数。它的另一个用处是,分析每个文件生成代码段的大小。对于一些小项目没什么用处,像QQ或微信这种超级App就比较有用了。因为苹果对上架的app有大小限制,代码段超过100M就不允许上架。(引用)
3.上面说到可以精确知道某个地址对应的函数。对, 这让我想到了之前的一个需求, 就是友盟崩溃解决任务, 然而友盟并没有捕捉到崩溃的方法,那我们怎么做呢?
第一种方法:
使用dwarfdump命令
dwarfdump --uuid xx.app.dSYM 用来得到app的UUID。
dwarfdump --lookup 0x12b45d -arch armv7 xx.app.dSYM 使错误的日志能看懂,把相应的内存地址对应到正确的地方。
如果一开始dwarfdump命令不能用的话,要先装Command Line Tools,这个在设置里面能下载(cmd+“,”打开设置)。另外还必须在进入.DSYM所在文件夹。
使用dwarfdump需要安装Command Line Tools,XCode里设置下载。而且需要进入.DSYM所在文件夹里进行操作。
使用xcrun atos命令
atos -o YourApp.app.dSYM/Contents/Resources/DWARF/YourApp 0x00062867
下面重点推荐下这个方法,方便快捷
下面这是我的项目里通过友盟统计到的崩溃日志,如果光看这些日志报告的话,是不会知道是哪行代码引起的。
使用方法是把对应版本的.xcarchive文件拖到工具。对比UUID和友盟里日志是否一致,一致就把错误的地址信息拷贝到箭头处。点击分析。
即可得出具体代码崩溃位置。很简单吧。
第二种方法和第三张方法都行,工具的下载地址:http://pan.baidu.com/s/1mg01Qha
总结: 以上分为三点,1重复资源如何查找进而处理 2认识可执行文件结构,以及linkmap文件的大小排布
3解决友盟没有捕捉到方法的崩溃
以上三点你学会了么, 如果学会了,这篇文章总算没有白整理, 希望获得你的喜欢或关注, 最主要的是支持哈。
网友评论
例如第二行代表了文件序号为2(反查上面就是TKPFileInfo.o)的parseWithDictionary方法占用了1000byte大小
应该是 1024byte大小吧