1. Clang编译
创建一个MacOS工程,我们编译里面的main.m文件。
编译命令:clang -rewrite-objc main.m -o main.cpp,通过该命令可以将main.m编译成一个cpp文件。
// macos命令行项目:
clang -rewrite-objc main.m -o main.cpp
clang -rewrite-objc
// 引用UIKit库
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk main.m
// xcrun xcode 命令:
xcrun -sdk iphonesimulator clang -arch -arm64 -rewrite-objc main.m -o main.m-arm64.cpp // 模拟器
xcrun -sdk iphoneos clang -arch -arm64 -rewrite-objc main.m -o main.m-arm64.cpp // 真机
2.编译结果
main.m内容如下:
#import <Foundation/Foundation.h>
@interface Person : NSObject {
NSString *nickname;
}
@property (weak, nonatomic) NSString * name;
@end
@implementation Person
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
}
return 0;
}
我们搜索Person 有124个结果
通过对比这些结果分析我们知道LGPerson编译后的结果如下cpp文件我们可以看到:
- 我们的Person类被编译为一个的
objc_object结构体: - 成员变量nickname还是nickname
- 属性name被编译成了_name
- 同时生成了name属性的getter和setter方法
#ifndef _REWRITER_typedef_Person
#define _REWRITER_typedef_Person
typedef struct objc_object Person;
typedef struct {} _objc_exc_Person;
#endif
extern "C" unsigned long OBJC_IVAR_$_Person$_name;
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *nickname;
NSString *_name;
};
// @property (copy, nonatomic) NSString * name;
/* @end */
// @implementation Person
static NSString * _I_Person_name(Person * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_Person$_name)); }
extern "C" __declspec(dllimport) void objc_setProperty (id, SEL, long, id, bool, bool);
static void _I_Person_setName_(Person * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct Person, _name), (id)name, 0, 1); }
// @end
我们再次进行全局 搜索 typedef struct objc_object得到843个结果,可见这个结构体一定定义了很多很多的东西。
那么objc_object在底层到底是什么东西呢,我们可以通过搜索objc_object {去寻找它的定义。通过搜索我们找到了objc_object的定义。再其上下还发现了Class和id以及SEL。
typedef struct objc_class *Class;
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
typedef struct objc_object *id;
typedef struct objc_selector *SEL;
由以上代码我们可以得到如下结论:
objc_object在底层是一个结构体id是一个objc_object类型的结构体指针SEL是一个objc_selector类型的结构体指针Class是一个objc_class类型的结构体指针
那么objc_selector和objc_class是怎么实现的呢,我们发现再次进行全局搜索相关字符后就找不到相关结果了。下面先来介绍一个通过clang编译后的Person相关的属性和方法签名相关知识。objc_class可以参考我的另一篇文章:iOS Objective-C 类原理,objc_selector可以参考objc_selector
3.方法列表和签名
注 : Xcode 11.5 (11E608c)
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[4];
} _OBJC_$_INSTANCE_METHODS_Person __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
4,
{{(struct objc_selector *)"name", "@16@0:8", (void *)_I_Person_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_Person_setName_},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_Person_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_Person_setName_}}
};
"@16@0:8"为方法签名:
- @ 为返回值类型
- 16 是所有参数所占内存长度
- @ 为第一个参数类型(id self)
- 0 是第一个参数的起始位置 (id 占8字节)
- :为第二个参数类型 (SEL cmd)
- 8 为第二个参数起始位置(如果参数多,可以以此类推)(SEL 占8字节)
各种类型对应符号:
- 打印:
void types(){
NSLog(@"char --> %s",@encode(char));
NSLog(@"int --> %s",@encode(int));
NSLog(@"short --> %s",@encode(short));
NSLog(@"long --> %s",@encode(long));
NSLog(@"long long --> %s",@encode(long long));
NSLog(@"unsigned char --> %s",@encode(unsigned char));
NSLog(@"unsigned int --> %s",@encode(unsigned int));
NSLog(@"unsigned short --> %s",@encode(unsigned short));
NSLog(@"unsigned long --> %s",@encode(unsigned long long));
NSLog(@"float --> %s",@encode(float));
NSLog(@"bool --> %s",@encode(bool));
NSLog(@"void --> %s",@encode(void));
NSLog(@"char * --> %s",@encode(char *));
NSLog(@"id --> %s",@encode(id));
NSLog(@"Class --> %s",@encode(Class));
NSLog(@"SEL --> %s",@encode(SEL));
int array[] = {1,2,3};
NSLog(@"int[] --> %s",@encode(typeof(array)));
typedef struct person{
char *name;
int age;
}Person;
NSLog(@"struct --> %s",@encode(Person));
typedef union union_type{
char *name;
int a;
}Union;
NSLog(@"union --> %s",@encode(Union));
int a = 2;
int *b = {&a};
NSLog(@"int[] --> %s",@encode(typeof(b)));
}
- 官方文档: