「類與對象」揭秘本質的第一步
- 2019 年 11 月 25 日
- 筆記
Objective-C本身是一種高級語言,底層都是由C/C++實現。
若想了解Objective-C一些API具體實現以及一些對象真實的數據結構等,就需要將Objective-C語言轉化成C/C++語言。
OC語言轉化成C/C++的相關命令
- 需要使用的命令:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
- 使用Xcode自帶的命令:xcrun;
- 選擇指定編譯平台(SDK):iphoneos,可通過下面的命令查看所有的支援的SDK,執行命令xcodebuild -sdks,結果如下:
- 選擇指定架構,可以選擇模擬器(i386)、x86_64、64bit(arm64)、32bit(armv7),由於IPhone屬於arm64架構,所以添加參數:-arch arm64
- 默認使用的是Clang編譯器:需要使用clang相關命令;
- 若想支援ARC,需要添加-fobjc-arc編譯參數;
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc main.m -o main.cpp
- 若想指定運行時的系統版本,可以添加-fobjc-runtime=ios-8.0.0:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m -o main.cpp
- 若需要指定框架:需要添加-framework 參數,比如-framework UIKIt:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m -o main.cpp -framework Foundation
… 還有許多
關於xcrun命令使用掌握上述幾種,就足以開發理解和使用了,許多其他用法就不在本文一一介紹了。
最終使用的命令:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
驗證本質
創建一個實例項目並將項目中的main.m轉換成main.cpp文件,具體展示如下:
(項目地址:https://github.com/123sunxiaolin/JLPractice/tree/master/JLClassAndObjPractice)
文件目錄相關截圖:
main.m相關程式碼:
int main(int argc, char * argv[]) { NSString * appDelegateClassName; @autoreleasepool { // Setup code that might create autoreleased objects goes here. appDelegateClassName = NSStringFromClass([AppDelegate class]); } return UIApplicationMain(argc, argv, nil, appDelegateClassName);}
main.cpp相關程式碼:
truct AppDelegate_IMPL { struct UIResponder_IMPL UIResponder_IVARS;};/* @end */ int main(int argc, char * argv[]) { NSString * appDelegateClassName; /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))); } return UIApplicationMain(argc, argv, __null, appDelegateClassName);}static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };
我想,大家剛開始做iOS開發的時候,心中總會有一個疑問:
創建的對象都是繼承自NSObject類,那NSObject類底層數據結構是什麼呢?
今天,就用上面的編譯命令,一探NSObject類真實面目!
1、在main.m文件中創建一個新的NSObject對象:
int main(int argc, char * argv[]) { NSString * appDelegateClassName; @autoreleasepool { // Setup code that might create autoreleased objects goes here. appDelegateClassName = NSStringFromClass([AppDelegate class]); // 創建一個NSObject對象 NSObject *obj = [[NSObject alloc] init]; } return UIApplicationMain(argc, argv, nil, appDelegateClassName);}
2、clang編譯後:
struct AppDelegate_IMPL { struct UIResponder_IMPL UIResponder_IVARS;}; int main(int argc, char * argv[]) { NSString * appDelegateClassName; /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))); NSObject *obj = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init")); } return UIApplicationMain(argc, argv, __null, appDelegateClassName);}
3、查看一下NSObject在Objective-C語言中的聲明:
@interface NSObject <NSObject> {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wobjc-interface-ivars" Class isa OBJC_ISA_AVAILABILITY;#pragma clang diagnostic pop} 精簡後:@interface NSObject <NSObject> { Class isa;}
那麼它對應的真實數據結構是什麼呢?
於是在剛剛編譯後的main.cpp文件中,搜索NSObject關鍵字,經過篩選比對,最後找到一個與上述NSObject結構相似的結構,如下所示:
struct NSObject_IMPL { Class isa;};
IMPL一般是implementation縮寫,從而從側面驗證了NSObject底層數據結構是結構體。
NSObject所對應的的結構體,僅包含一個成員變數isa,isa主要存放Objective-C對象的地址。
今天先到這。