在Objective-C類成員變量深度剖析一文中,做者經過分析Clang生成的LLVM中間碼得出了以下結論:html
LLVM爲每一個類的每一個成員變量都分配了一個全局變量,用於存儲該成員變量的偏移值。
結論是對的,但要讀LLVM中間碼,難免使人頭大。一個簡單的辦法是用git
Clang -rewrite-objc *.m
將OC代碼轉換成C++代碼,而後分析C++代碼便可。github
以Command Line Tool模板爲例,好比shell
//Dummy.h @interface Dummy : NSObject { @public int myInt; } @end //Dummy.m @implementation Dummy @end
在main.m中,有atom
#import <Foundation/Foundation.h> #import "Dummy.h" int main(int argc, const char * argv[]) { Dummy *dummy = [Dummy new]; dummy->myInt; return 0; }
執行code
Clang -rewrite-objc main.m
打開生成的main.cpp,能夠看到htm
//Foundation.h展開後的一大堆C++定義 //... /* @end */ #ifndef _REWRITER_typedef_Dummy #define _REWRITER_typedef_Dummy typedef struct objc_object Dummy; typedef struct {} _objc_exc_Dummy; #endif extern "C" unsigned long OBJC_IVAR_$_Dummy$myInt; struct Dummy_IMPL { struct NSObject_IMPL NSObject_IVARS; int myInt; }; /* @end */ int main(int argc, const char * argv[]) { Dummy *dummy = ((Dummy *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Dummy"), sel_registerName("new")); (*(int *)((char *)dummy + OBJC_IVAR_$_Dummy$myInt)); return 0; }
其中OBJC_IVAR_$_Dummy$myInt就是存儲Dummy的myInt成員變量偏移值的全局變量。get
若是用@property,會稍微複雜一些,好比cmd
//Dummy.h @interface Dummy : NSObject @property (nonatomic, assign) int myInt; @end //Dummy.m @implementation Dummy @end
執行it
Clang -rewrite-objc Dummy.m
打開生成的Dummy.cpp,能夠看到
extern "C" unsigned long OBJC_IVAR_$_Dummy$_myInt; struct Dummy_IMPL { struct NSObject_IMPL NSObject_IVARS; int _myInt; }; // @property (nonatomic, assign) int myInt; /* @end */ // @implementation Dummy static int _I_Dummy_myInt(Dummy * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_Dummy$_myInt)); } static void _I_Dummy_setMyInt_(Dummy * self, SEL _cmd, int myInt) { (*(int *)((char *)self + OBJC_IVAR_$_Dummy$_myInt)) = myInt; } // @end
對應property的setter和getter,Clang相應地生成了兩個static function,二者都經過OBJC_IVAR_$_Dummy$myInt來訪問myInt。