Objective-C的面向对象都是基于C/C++的数据结构实现的。Objective-C的对象,类主要基于C/C++的结构体实现的。
一、 clang
Clang是⼀个C语⾔、C++、Objective-C语⾔的轻量级编译器。源代码发布于BSD协议下。Clang将⽀持其普通lambda表达式、返回类型的简化处理以及更好的处理constexpr关键字。Clang是⼀个由Apple主导编写,基于LLVM的C/C++/Objective-C编译器- 2013年4⽉,
Clang已经全⾯⽀持C++11标准,并开始实现C++1y特性(也就是C++14),这是C++的下⼀个⼩更新版本)。 Clang是⼀个C++编写、基于LLVM、发布于LLVMBSD许可证下的C/C++/Objective-C/Objective-C++编译器。它与GNU C语⾔规范⼏乎完全兼容(当然,也有部分不兼容的内容,包括编译命令选项也会有点差异),并在此基础上增加了额外的语法特性,⽐如C函数重载(通过__attribute__((overloadable))来修饰函数),其⽬标(之⼀)就是超越GCC。
clang编译c++文件:
clang -rewrite-objc main.m -o main.cpp把⽬标⽂件编译成c++⽂件UIKit报错问题:
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m
-
xcode安装的时候顺带安装了xcrun命令,xcrun命令在clang的基础上进⾏了⼀些封装,要更好⽤⼀些。 -
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp (模拟器) -
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp (⼿机)
二、.m 文件生成 .cpp 文件
通过:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Objective-C源文件 -o 目标c或者cpp文件,在 arm64 环境下,生成的 cpp 文件中, SHPerson 对象被转成了:
struct SHPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_name;
};
NSObject_IMPL 的结构:
struct NSObject_IMPL {
Class isa;
};
所以本质上 SHPerson 的结构为:
struct SHPerson_IMPL {
Class isa;
NSString *_name;
};
三、.cpp文件的getter 和 setter
1. 在转成 cpp 文件后,name 属性的 getter
static NSString * _I_SHPerson_name(SHPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_SHPerson$_name)); }
它的返回值是个 self + OBJC_IVAR_$_SHPerson$_name,是因为 self + OBJC_IVAR_$_SHPerson$_name 是 name 的值的存储的地方,可以认为在获取 name 的值的时候是通过内存平移的方式获取的。
2. setter 方法
setter 方法的生成有点特殊,在用 strong 修饰的时候长这样:
static void _I_SHPerson_setName_(SHPerson * self, SEL _cmd, NSString *name) { (*(NSString **)((char *)self + OBJC_IVAR_$_SHPerson$_name)) = name; }
用 copy 修饰的时候长这样:
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_SHPerson_setName_(SHPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct SHPerson, _name), (id)name, 0, 1); }
这是因为系统在对用 copy 修饰的属性进行了特殊的处理。
另外,在平时写 OC 写的 setter 和 getter 中,发现并没有 SHPerson * self, SEL _cmd 这两个参数,但 clang 编译成的 C++ 文件中有。是因为 SHPerson * self, SEL _cmd 是这两个方法的隐藏参数,这也就是为什么我们在实例方法里面都可以使用 self 的原因。