「類與對象」揭秘本質的第一步

  • 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、查看一下NSObjectObjective-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對象的地址

今天先到這。