iOS App启动优化:利用 __attribute__((used, section (“name“)))处理静态协议

在平时的开发过程中,我们往往会注册一些如跳转,模板类型这类的静态协议,一般的处理方式有两种:

  • 使用静态文件,如plist,json文件注册:

{"home":"jump1","my":"jump2"
    ...
}
  • load方法中动态注册:

+(void)load {ProtocolRegister(home,jump1)}

第一种方式如果在单个模块内使用问题不大,如果跨模块使用多人修改,很容易出问题;第二种方式虽然不会出现第一种方式那种情况,但是因为在load方法中,数量多了,会拖慢App的启动速度。再者,由于都是静态协议,并不需要动态注册。那么,有没有什么方式可以在编译期/静态链接期间就可以生成静态协议呢?

attribute

attribute是编译属性,用于改变所声明或定义的函数或数据的特性,比如存储特性。attribute中有很多属性,现在我们可以通过 __attribute__((section("name")))编译属性将数据写到可执行文件中,然后在使用的时候,从可执行文件中读取出来。

首先,因为是key-value的形式,我们可以先定义一个结构体:

structProtocolInfo{char*key;char*value;};

然后,使用宏定义一段使用__attribute__((section("name"))) 的代码段:

#define ProtocolRegister(_key_,_value_)\
__attribute__((used)) static struct ProtocolInfo ProtocolInfo##_key_ \
__attribute__ ((used, section ("__DATA,ProtocolInfoData"))) =\
{\
    .key = #_key_,\
    .value = #_value_,\
};

used是告诉编译器不用优化掉此函数,即使没有地方使用。ProtocolInfoData 名字可以自定义,除了结构体,char,int 类型也可以使用。这样我们就可以将协议数据写到可执行文件的__DATA 字段中了。

使用方式:

ProtocolRegister(home,jump1)ProtocolRegister(my,jump2)

在可执行文件(Mach-O)中的格式如下:

Mach-O文件

最后,我们需要在使用的时候从可执行文件中读取:

#include <dlfcn.h>
#include <mach-o/getsect.h>

...

- (void)readDataFromMachO {
    //1.根据符号找到所在的mach-o文件信息
        Dl_info info;
        dladdr((__bridge void *)[self class], &info);
    
    //2.读取__DATA中自定义的ProtocolInfoDataz数据
    #ifndef __LP64__
        const struct mach_header *mhp = (struct mach_header*)info.dli_fbase;
        unsigned long schemeSize = 0;
        uint32_t *schemeMemory = (uint32_t*)getsectiondata(mhp, "__DATA", "ProtocolInfoData", &schemeSize);
    #else /* defined(__LP64__) */
        const struct mach_header_64 *mhp = (struct mach_header_64*)info.dli_fbase;
        unsigned long schemeSize = 0;
        uint64_t *schemeMemory = (uint64_t*)getsectiondata(mhp, "__DATA", "ProtocolInfoData", &schemeSize);
     
    #endif /* defined(__LP64__) */
    
    //3.遍历ProtocolInfoData中的协议数据
    unsigned long schemeCounter = schemeSize/sizeof(struct ProtocolInfo);
    struct ProtocolInfo *items = (struct ProtocolInfo*)schemeMemory;
    for(int idx = 0; idx < schemeCounter; ++idx){
        NSString * key = [NSString stringWithUTF8String:items[idx].key];
        NSString * value = [NSString stringWithUTF8String:items[idx].value];;
        NSLog(@"-------------key:%@ , value:%@",key,value);
    
    }
}

除了__attribute__((section("name"))) ,常用的如使用__attribute__((constructor))修饰的函数可以在main函数之前调用 ,可以替换load方法使用。更多的__attribute__用法,有兴趣的可以查看:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/BABCJJID.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值