对象与方法的本质

方法:

通过前面一篇 从 MachO 加载到对象创建! 可以了解到 allocinit 方法的底层, 接下来看方法的实质:

定义类 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 可以代表一个对象;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。