//代碼片段摘自蘋果開源的runtime代碼(objc4-208版本)
//https://opensource.apple.com/source/objc4/objc4-208/runtime/objc-class.h
struct objc_class {
struct objc_class *isa;
struct objc_class *super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
#if defined(Release3CompatibilityBuild)
struct objc_method_list *methods;
#else
struct objc_method_list **methodLists;
#endif
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
這是Objective-C 2.0中的類的代碼,相信做iOS開發(fā)的同學都很熟悉的了冤议。有天在查資料又看到它的時候斟薇,想到了一個好奇的問題:
methodLists
是一個二級指針,在內存中恕酸,它指向的是什么呢堪滨?(或者說,其指向的數據結構到底是怎么樣的蕊温?)
然后袱箱,我想到了下面幾個可能性:
-
methodLists
指向的是一個結構體的指針 methodLists
指向的是結構體數組的指針
-
methodLists
指向的是結構體指針數組
那么上面的可能性都是存在的嗎遏乔?為了驗證,我寫了下面的代碼進行測試发笔。
#include <stdio.h>
typedef struct {
float version;
} method;
int main(int argc, char const *argv[]) {
method **methodList;
method aMethod;
aMethod.version = 1.1;
method bMethod;
bMethod.version = 2.2;
printf("開始驗證第1種可能性:aP->bP->obj\n");
method *aMethodP = &aMethod;
methodList = &aMethodP;
method* currentMethod = *methodList;
float version = currentMethod->version;
printf("version:%0.1f\n",version);
printf("結束驗證第1種可能性按灶。\n");
printf("開始驗證第2種可能性:aP->bP->obj[]\n");
method methodArray[2];
methodArray[0] = aMethod;
methodArray[1] = bMethod;
*methodList = methodArray;
for (size_t i = 0; i < 2; i++) {
method* currentMethod = &((*methodList)[i]);
float version = currentMethod->version;
printf("version:%0.1f\n",version);
}
printf("結束驗證第2種可能性。\n");
printf("開始驗證第3種可能性:aP->[(bP->obj)]\n");
method* methodPointArray[2];
methodPointArray[0]=&aMethod;
methodPointArray[1]=&bMethod;
methodList = &(methodPointArray[0]);
for (size_t i = 0; i < 2; i++) {
method* currentMethod = *(methodList+i);
float version = currentMethod->version;
printf("version:%0.1f\n",version);
}
printf("結束驗證第3種可能性筐咧。\n");
return 0;
}
運行結果如下:
按照上面提出的模型所編寫的代碼可以運行通過鸯旁,這證明所說的3種可能性都存在,然而在runtime
里使用的是哪種呢量蕊?
為此铺罢,特意去看了相關的代碼,得到的答案是:第三種残炮。
論據為:runtime
中的class
移除method
的方法代碼:
//代碼片段摘自蘋果開源的runtime代碼(objc4-208版本)
//https://opensource.apple.com/source/objc4/objc4-208/runtime/objc-class.m
void class_removeMethods (Class cls, struct objc_method_list * meths)
{
// Remove atomically.
_objc_removeMethods (meths, &((struct objc_class *) cls)->methodLists);
// Must flush when dynamically removing methods. No need to flush
// all the class method caches. If cls is a meta class, though,
// this will still flush it and any of its sub-meta classes.
flush_caches (cls, NO);
}
//代碼片段摘自蘋果開源的runtime代碼(objc4-208版本)
//https://opensource.apple.com/source/objc4/objc4-208/runtime/objc-runtime.m
void _objc_removeMethods (struct objc_method_list * mlist, struct objc_method_list *** list)
{
struct objc_method_list ** ptr;
// Locate list in the array
ptr = *list;
while (*ptr != mlist) {
// fix for radar # 2538790
if ( *ptr == END_OF_METHODS_LIST ) return;
ptr += 1;
}
// Remove this entry
*ptr = 0;
// Left shift the following entries
while (*(++ptr) != END_OF_METHODS_LIST)
*(ptr-1) = *ptr;
*(ptr-1) = 0;
}
寫在最后
那么對于標題提出的問題:『二級指針指向的數據結構是什么樣的韭赘?』,它的標準答案是什么呢势就?
答案是:沒有標準答案泉瞻,它的答案應該是結合具體的業(yè)務代碼來回答的,比如Runtime
里的methodLists
苞冯。
另外袖牙,在最后,不得不感嘆下:指針真是C語言的靈魂舅锄,其讓C變得何其靈活1薮铩(當然,同時也讓C變得復雜皇忿,在你不知道作者的指針意圖的時候)