__data在编译阶段处理协议

#问题:如果某些业务场景下,需要很早的注册一些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文件](https://upload-images.jianshu.io/upload_images/9833310-45cd7095b9e7b70f.png?imageMogr2/auto-orient/strip|imageView2/2/w/343) ## 读取 ``` #include #include ... - (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在编译阶段处理协议)