您现在的位置是:首页 >学无止境 >iOS无用类统计方案网站首页学无止境
iOS无用类统计方案
简介iOS无用类统计方案
网上能搜到各种无用类统计,多数是通过对编译产物进行分析。类似这种方案有个问题:如果类被引用但实际上用户已不会访问到,这种是束手无策的。
新方案
前年在公司做了个新的方案,主要技术点是利用OC类初始化标记initialized
,学习过objc源码的同学应该熟悉,类初始化之后有个bit位被标记为1,因此在特定的时机遍历工程所有类,并检查这个比特位是否为1即可筛选出所有被使用过或未被用过的类。
代码如下:
#define FAST_DATA_MASK 0x00007ffffffffff8UL
#define RW_INITIALIZED (1<<29)
/*
// objc_class 代码片段
struct objc_class : objc_object {//8bytes
// Class ISA;
Class superclass; //8bytes
cache_t cache; //16bytes
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
...
class_rw_t *data() const {
return bits.data();
}
...
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
...
}
*/
bool class_hasInitialized(const char * _Nullable className) {
Class metaCls = objc_getMetaClass(className);
if (metaCls) {
// https://opensource.apple.com/source/objc4/objc4-787.1/runtime/objc-runtime-new.h.auto.html
uint64_t *bits = (__bridge void *)metaCls + 32;
uint32_t *data = (uint32_t *)(*bits & FAST_DATA_MASK);
uint64_t result = (*data & RW_INITIALIZED);
return result != 0;
}
return false;
}
核心代码很简单,获取工程所有类可以参考之前的文章
大概的统计思路:
前端
前端负责上传使用过的类
- 检测到用户升级新版本后,把所有类写入KV
- 定时/特定时机遍历KV中的所有类,检查是否被初始化,将被初始化的从KV中移除并上传后台(即端上KV中保留的总是未使用的,上传的总是新增的使用过的)
后端
后端通过集合取差集的方式统计所有未使用过的类
- 在接收到用户上传时,如果后端没有所有类的集合,则给客户端返回一个特定code,端上据此上传全量类的集合
- 端上根据全量类的集合以及用户上传的使用过的集合做差集,即为未使用过的集合。
逻辑增强
统计是针对版本进行的,因此为了数据更精确可以针对每个版本的统计数据做最近n个版本的交集,表示最近n个版本都未使用过。如此以来删无用代码的确认压力可以减小很多。
问题
- 无法统计纯Swift类,因为纯Swift是静态类不走runtime这一套
- 无法处理那些被初始化,但实际并未被使用的类
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。