- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- iOS中怎么刪除無(wú)用的類(lèi)
本篇文章給大家分享的是有關(guān)iOS中怎么刪除無(wú)用的類(lèi),小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習,希望大家閱讀完這篇文章后可以有所收獲,話(huà)不多說(shuō),跟著(zhù)小編一起來(lái)看看吧。
引用類(lèi)地址
可以通過(guò)Mac自帶的工具otool打印Mach-o中的段信息,需要注意的是模擬器和真機對應的可執行文件,數據的存儲方式不同需要加以區分。
可以通過(guò)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()
在取類(lèi)地址的時(shí)候區分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
通過(guò)otool -v -s __DATA __objc_classrefs獲取到引用類(lèi)的地址。
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
所有類(lèi)地址
通過(guò)otool -v -s __DATA __objc_classlist獲取所有類(lèi)的地址。
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
取差集
用所有類(lèi)信息減去引用類(lèi)的信息,此時(shí)我們可以拿到未使用類(lèi)的地址信息。
unref_pointers = class_list_pointers(path, binary_file_arch) - class_ref_pointers(path, binary_file_arch)
符號化
通過(guò)nm -nm命令可以得到地址和對應的類(lèi)名字。
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
過(guò)濾
在實(shí)際分析的過(guò)程中發(fā)現,如果一個(gè)類(lèi)的子類(lèi)被實(shí)例化,父類(lèi)未被實(shí)例化,此時(shí)父類(lèi)不會(huì )出現在__objc_classrefs這個(gè)段里,在未使用的類(lèi)中需要將這一部分父類(lèi)過(guò)濾出去。使用otool -oV可以獲取到類(lèi)的繼承關(guān)系。
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
為了防止一些三方庫的誤傷,還可以去過(guò)濾一些前綴,或者是是僅保留帶有某些前綴的類(lèi)。
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()
這個(gè)思路在一定程度上能夠減少代碼的冗余,減小包的體積。因為是靜態(tài)分析,不能包括動(dòng)態(tài)調用的情況,對于需要刪除的類(lèi)需要進(jìn)一步的確認。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站