在平時(shí)的開發(fā)過程中初狰,我們往往會(huì)注冊一些如跳轉(zhuǎn),模板類型這類的靜態(tài)協(xié)議,一般的處理方式有兩種:
-
使用靜態(tài)文件霎挟,如plist逊桦,json文件注冊:
{ "home":"jump1", "my":"jump2" ... }
-
load方法中動(dòng)態(tài)注冊:
+ (void)load { ProtocolRegister(home,jump1) }
第一種方式如果在單個(gè)模塊內(nèi)使用問題不大备绽,如果跨模塊使用多人修改希太,很容易出問題沼瘫;第二種方式雖然不會(huì)出現(xiàn)第一種方式那種情況每窖,但是因?yàn)樵趌oad方法中帮掉,數(shù)量多了,會(huì)拖慢App的啟動(dòng)速度窒典。再者蟆炊,由于都是靜態(tài)協(xié)議,并不需要?jiǎng)討B(tài)注冊瀑志。那么涩搓,有沒有什么方式可以在編譯期/靜態(tài)鏈接期間就可以生成靜態(tài)協(xié)議呢?
attribute
attribute是編譯屬性劈猪,用于改變所聲明或定義的函數(shù)或數(shù)據(jù)的特性昧甘,比如存儲(chǔ)特性。attribute中有很多屬性战得,現(xiàn)在我們可以通過 __attribute__((section("name")))
編譯屬性將數(shù)據(jù)寫到可執(zhí)行文件中充边,然后在使用的時(shí)候,從可執(zhí)行文件中讀取出來常侦。
首先浇冰,因?yàn)槭莐ey-value的形式贬媒,我們可以先定義一個(gè)結(jié)構(gòu)體:
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是告訴編譯器不用優(yōu)化掉此函數(shù)肘习,即使沒有地方使用际乘。ProtocolInfoData
名字可以自定義,除了結(jié)構(gòu)體井厌,char
,int
類型也可以使用致讥。這樣我們就可以將協(xié)議數(shù)據(jù)寫到可執(zhí)行文件的__DATA
字段中了仅仆。
使用方式:
ProtocolRegister(home,jump1)
ProtocolRegister(my,jump2)
在可執(zhí)行文件(Mach-O
)中的格式如下:
最后,我們需要在使用的時(shí)候從可執(zhí)行文件中讀裙父ぁ:
#include <dlfcn.h>
#include <mach-o/getsect.h>
...
- (void)readDataFromMachO {
//1.根據(jù)符號(hào)找到所在的mach-o文件信息
Dl_info info;
dladdr((__bridge void *)[self class], &info);
//2.讀取__DATA中自定義的ProtocolInfoDataz數(shù)據(jù)
#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中的協(xié)議數(shù)據(jù)
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))
修飾的函數(shù)可以在main函數(shù)之前調(diào)用 ,可以替換load方法使用请契。更多的__attribute__
用法咳榜,有興趣的可以查看:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/BABCJJID.html