1. Clang简介
Clang是一个C语言、C++、Objective-C语言的轻量级编译器
。
Clang将支持其普通lambda表达式
、返回类型的简化处理
以及更好的处理constexpr
关键字。
它与GNU C语言规范几乎完全兼容
(当然也有部分不兼容的内容, 包括编译命令选项也会有点差异),并在此基础上增加了额外的语法特性,
比如C函数重载 (通过__attribute__((overloadable))
来修饰函数).
2. OC对象的clang编译
2.1 新建控制台工程
2.2 在main.m中定义类HTPerson和对象person
@interface HTPerson : NSObject
@property(nonatomic,strong)NSString *name;
@end
@implementation HTPerson
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
HTPerson *person = [[HTPerson alloc]init];
NSLog(@"Hello, World!");
}
return 0;
}
2.3.终端使用clang编译main.m生成main.cpp
clang -rewrite-objc main.m -o main.cpp
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
2.4 打开main.cpp并找到HTPerson类
可以观察到HTPerson类编译成了一个struct,在OC中类的本质就是结构体(struct)
- struct 的成员变量
struct NSObject_IMPL NSObject_IVARS
和在HTPerson类中定义的属性_name.
其中struct NSObject_IMPL NSObject_IVARS就是我们常说的isa
.
-
struct 的成员函数
属性name的setter :
_I_HTPerson_setName_
属性name的getter方法 :
_I_HTPerson_name
-->objc_setProperty
注:属性的所有setter方法都会进入objc_setProperty方法中
#ifndef _REWRITER_typedef_HTPerson
#define _REWRITER_typedef_HTPerson
typedef struct objc_object HTPerson;
typedef struct {} _objc_exc_HTPerson;
#endif
extern "C" unsigned long OBJC_IVAR_$_HTPerson$_name;
struct HTPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_name;
};
// @property(nonatomic,copy)NSString *name;
/* @end */
// @implementation HTPerson
static NSString * _I_HTPerson_name(HTPerson * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_HTPerson$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_HTPerson_setName_(HTPerson * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct HTPerson, _name), (id)name, 0, 1); }
OC中的所有set方法,都会进
objc_setProperty
-->reallySetProperty
reallySetProperty源码解析:
从.cpp代码中可以看到,OC代码
HTPerson *person = [HTPerson alloc];
编译器编译后可用C++代码替换为:
HTPerson *person = ((HTPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("HTPerson"), sel_registerName("alloc"));
//HTPerson *person = objc_msgSend(objc_getClass("HTPerson"), sel_registerName("alloc"));
其中self
,_cmd
是消息底层默认的两个参数id(消息接受者)
,SEL(消息编号)
objc_msgSend
末尾可继续加参数
,但是考虑到编译参数问题,我们需要关闭严格核查
2.5 对象方法调用
HTPerson *person = [HTPerson alloc];
objc_msgSend(person,sel_registerName("sayNB"));
[person sayNB];
注意:
- 1)直接调用objc_msgSend,需要导入头文件
#import <objc/message.h>
- 2)需要将target --> Build Setting -->搜索msg -- 将
enable strict checking of obc_msgSend calls由YES 改为NO
,关闭严格核查,否则objc_msgSend的参数会报错
2.6 对象方法调用(继承自父类的方法):objc_msgSendSuper
HTPerson *person = [HTPerson alloc];
HTTeacher *teacher = [HTTeacher alloc];
[person sayHello];
struct objc_super lgsuper;
lgsuper.receiver = person; //消息的接收者 person
lgsuper.super_class = [HTTeacher class]; //指定父类
objc_msgSendSuper(&lgsuper, sel_registerName("sayHello"));