iOS中怎么删除无用的类
本篇文章给大家分享的是有关iOS中怎么删除无用的类,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
引用类地址
可以通过Mac自带的工具otool打印Mach-o中的段信息,需要注意的是模拟器和真机对应的可执行文件,数据的存储方式不同需要加以区分。
可以通过file命令获取到arch。
#binary_file_arch: distinguish Big-Endian and Little-Endian#file -b output example: Mach-O 64-bit executable arm64binary_file_arch = os.popen('file -b ' + path).read().split(' ')[-1].strip()
在取类地址的时候区分x86_64和arm。
def pointers_from_binary(line, binary_file_arch): line = line[16:].strip().split(' ') pointers = set() if binary_file_arch == 'x86_64': #untreated line example:00000001030cec80d8 75 15 03 01 00 00 00 68 77 15 03 01 00 00 00 pointers.add(''.join(line[4:8][::-1] + line[0:4][::-1])) pointers.add(''.join(line[12:16][::-1] + line[8:12][::-1])) return pointers #arm64 confirmed,armv7 arm7s unconfirmed if binary_file_arch.startswith('arm'): #untreated line example:00000001030bcd2003138580 00000001 03138878 00000001 pointers.add(line[1] + line[0]) pointers.add(line[3] + line[2]) return pointers return None
通过otool -v -s __DATA __objc_classrefs获取到引用类的地址。
def class_ref_pointers(path, binary_file_arch): ref_pointers = set() lines = os.popen('/usr/bin/otool -v -s __DATA __objc_classrefs %s' % path).readlines() for line in lines: pointers = pointers_from_binary(line, binary_file_arch) ref_pointers = ref_pointers.union(pointers) return ref_pointers
所有类地址
通过otool -v -s __DATA __objc_classlist获取所有类的地址。
def class_list_pointers(path, binary_file_arch): list_pointers = set() lines = os.popen('/usr/bin/otool -v -s __DATA __objc_classlist %s' % path).readlines() for line in lines: pointers = pointers_from_binary(line, binary_file_arch) list_pointers = list_pointers.union(pointers) return list_pointers
取差集
用所有类信息减去引用类的信息,此时我们可以拿到未使用类的地址信息。
unref_pointers = class_list_pointers(path, binary_file_arch) - class_ref_pointers(path, binary_file_arch)
符号化
通过nm -nm命令可以得到地址和对应的类名字。
def class_symbols(path): symbols = {} #class symbol format from nm: 0000000103113f68 (__DATA,__objc_data) external _OBJC_CLASS_$_EpisodeStatusDetailItemView re_class_name = re.compile('(\w{16}) .* _OBJC_CLASS_\$_(.+)') lines = os.popen('nm -nm %s' % path).readlines() for line in lines: result = re_class_name.findall(line) if result: (address, symbol) = result[0] symbols[address] = symbol return symbols
过滤
在实际分析的过程中发现,如果一个类的子类被实例化,父类未被实例化,此时父类不会出现在__objc_classrefs这个段里,在未使用的类中需要将这一部分父类过滤出去。使用otool -oV可以获取到类的继承关系。
def filter_super_class(unref_symbols): re_subclass_name = re.compile("\w{16} 0x\w{9} _OBJC_CLASS_\$_(.+)") re_superclass_name = re.compile("\s*superclass 0x\w{9} _OBJC_CLASS_\$_(.+)") #subclass example: 0000000102bd8070 0x103113f68 _OBJC_CLASS_$_TTEpisodeStatusDetailItemView #superclass example: superclass 0x10313bb80 _OBJC_CLASS_$_TTBaseControl lines = os.popen("/usr/bin/otool -oV %s" % path).readlines() subclass_name = "" superclass_name = "" for line in lines: subclass_match_result = re_subclass_name.findall(line) if subclass_match_result: subclass_name = subclass_match_result[0] superclass_match_result = re_superclass_name.findall(line) if superclass_match_result: superclass_name = superclass_match_result[0] if len(subclass_name) > 0 and len(superclass_name) > 0: if superclass_name in unref_symbols and subclass_name not in unref_symbols: unref_symbols.remove(superclass_name) superclass_name = "" subclass_name = "" return unref_symbols
为了防止一些三方库的误伤,还可以去过滤一些前缀,或者是是仅保留带有某些前缀的类。
for unref_pointer in unref_pointers: if unref_pointer in symbols: unref_symbol = symbols[unref_pointer] if len(reserved_prefix) > 0 and not unref_symbol.startswith(reserved_prefix): continue if len(filter_prefix) > 0 and unref_symbol.startswith(filter_prefix): continue unref_symbols.add(unref_symbol)
最终结果保存在脚本目录下。
script_path = sys.path[0].strip()f = open(script_path+"/result.txt","w")f.write( "unref class number: %d\n" % len(unref_symbles))f.write("\n")for unref_symble in unref_symbles: f.write(unref_symble+"\n")f.close()
这个思路在一定程度上能够减少代码的冗余,减小包的体积。因为是静态分析,不能包括动态调用的情况,对于需要删除的类需要进一步的确认。
以上就是iOS中怎么删除无用的类,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注恰卡编程网行业资讯频道。
推荐阅读
-
ios14系统怎么用nfc(ios 14新增的nfc功能怎么用)
ios14新增的nfc功能怎么用?1.打开iPhone后,选择手机的[设置]图标。2.进入后,点击【通用】选项进入。3.单击并选...
-
微信小程序iOS端怎么暂停animated动画
-
iOS中多线程的示例分析
-
ios启动私有链查询区块信息的方法是什么
ios启动私有链查询区块信息的方法是什么本篇内容介绍了“ios启动...
-
正则表达式在ios中怎么用
正则表达式在ios中怎么用这篇文章主要为大家展示了“正则表达式在i...
-
如何进行iOS中的信息泄露漏洞CVE-2020-9964分析
如何进行iOS中的信息泄露漏洞CVE-2020-9964分析今天就...
-
iOS中怎么实现一个序列动画
这篇文章给大家介绍iOS中怎么实现一个序列动画,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。UIViewPr...
-
iOS中怎么利用MVVM实现路由
iOS中怎么利用MVVM实现路由,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更...
-
iOS中怎么判断当前网络环境
本篇文章为大家展示了iOS中怎么判断当前网络环境,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所...
-
iOS中怎么改变UIBarButtonItem的大小
今天就跟大家聊聊有关iOS中怎么改变UIBarButtonItem的大小,可能很多人都不太了解,为了让大家更加了解,小编给大家总结...