「类与对象」揭秘本质的第一步

  • 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对象的地址

今天先到这。