美文网首页
__data在编译阶段处理协议

__data在编译阶段处理协议

作者: _叮叮当当__ | 来源:发表于2020-06-28 17:59 被阅读0次

    问题:如果某些业务场景下,需要很早的注册一些key-value? 怎么办?

    很多同学第一反应是+Load方法中进行注册;

    当然可以,如果需要在程序编译/链接期间就执行呢?

    答案:

    可以,我们可以通过attribute((section("name")))编译属性将数据写到可执行文件中,然后在使用的时候,从可执行文件中读取出来.

    解释:

    attribute是编译属性,用于改变所声明或定义的函数或数据的特性,比如存储特性。

    首先定义一个结构体:

    struct ProtocolInfo{
        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方法使用。

    相关文章

      网友评论

          本文标题:__data在编译阶段处理协议

          本文链接:https://www.haomeiwen.com/subject/ooiwfktx.html