方法:
通过前面一篇 从 MachO 加载到对象创建! 可以了解到 alloc
及 init
方法的底层, 接下来看方法的实质:
定义类 WXPerson
, 包含方法 run
;
创建 person 对象:
WXPerson * person = [[WXPerson all] init];
[person run];
通过编译器编译来看对象及方法的实质:
通过终端命令 clang -rewrite-objc main.m
可以获得同级目录下 main.cpp
文件, 查看文件发现, 上面创建对象及调用方法被编译成如下代码:
由于代码太长选择图片格式:
可以看到很多类型强转, 去掉类型强转:
WXPerson * person = objc_msgSend(
objc_msgSend(
objc_getClass("WXPerson"),
sel_registerName("alloc")),
sel_registerName("init"));
objc_msgSend(person,
sel_registerName("run"));
可以看到:
- 每次方法的调用都被编译成了消息发送
objc_msgSend
; - 调用
alloc
类方法是通过objc_getClass
获取类对象进行调用; - @selector() 会编译为
sel_registerName
方法, 向编译器注册一个方法;
补充: 由于该方法调用非常频繁, 且 C / C++ 方法不能动态保存方法的参数, 需要通过汇编通过寄存器读取动态参数, 所以苹果把该方法用汇编实现(具体见 libobjc.A.dylib -> objc-msg-*.s):
前面文章已有涉及: +load VS +initialize
对象:
查看上面编译好的 main.cpp 文件:
typedef struct objc_object WXPerson;
typedef struct {} _objc_exc_WXPerson;
struct WXPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
struct NSObject_IMPL {
Class isa;
};
可以发现 WXPerson
类被编译为 typedef struct objc_object WXPerson
结构体
而 objc_object
定义如下:
typedef struct objc_class *Class;
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
typedef struct objc_object *id;
typedef struct objc_selector *SEL;
至此可以看出:
- 对象的本质是结构体;
- 对象包含一个指向
objc_class
结构体的 isa; - 所以
id
可以代表一个对象;
网友评论