对象的本质

前面我们分析了对象的创建过程,那么对象的本质是什么呢?我们知道,OC 是通过 LLVM 编译的,而 clangLLVM 的编译前端,我们可以通过 clang 来一探究竟。

clang 编译源文件

我们从简单的 mian.m 文件开始:

@interface SMBook : NSObject {
NSString *_author;
}

@property (nonatomic, copy) NSString *name;

@end

@implementation SMBook

@end

int main(int argc, const char * argv[]) {
@autoreleasepool {
SMBook *book = [SMBook alloc];
book.name = @"程序员的自我修养";
}
return 0;
}

然后用 clang 命令:

clang -rewrite-objc main.m -o main.cpp

得到 main.cpp 文件。文件很长,因为包括编译链接的文件等。

编译后文件解析

我们打开 main.cpp 文件,直接滑到最底端,能看到我们的 SMBook

....
#pragma section(".objc_inithooks$B", long, read, write)
__declspec(allocate(".objc_inithooks$B")) static void *OBJC_CLASS_SETUP[] = {
(void *)&OBJC_CLASS_SETUP_$_SMBook,
};
static struct _class_t *L_OBJC_LABEL_CLASS_$ [1] __attribute__((used, section ("__DATA, __objc_classlist,regular,no_dead_strip")))= {
&OBJC_CLASS_$_SMBook,
};
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

对象构造函数

老套路,我们通过搜索查找我们的 OBJC_CLASS_SETUP_$_SMBook

static void OBJC_CLASS_SETUP_$_SMBook(void ) {
OBJC_METACLASS_$_SMBook.isa = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_SMBook.superclass = &OBJC_METACLASS_$_NSObject;
OBJC_METACLASS_$_SMBook.cache = &_objc_empty_cache;
OBJC_CLASS_$_SMBook.isa = &OBJC_METACLASS_$_SMBook;
OBJC_CLASS_$_SMBook.superclass = &OBJC_CLASS_$_NSObject;
OBJC_CLASS_$_SMBook.cache = &_objc_empty_cache;
}

这是一个构造函数:

  • 元类相关的 isasuperclasscache
  • 类相关的 isasuperclasscache

类的 isa 指向 OBJC_METACLASS_$_SMBook

extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_SMBook __attribute__ ((used, section ("__DATA,__objc_data"))) = {
0, // &OBJC_METACLASS_$_NSObject,
0, // &OBJC_METACLASS_$_NSObject,
0, // (void *)&_objc_empty_cache,
0, // unused, was (void *)&_objc_empty_vtable,
&_OBJC_METACLASS_RO_$_SMBook,
};

注意这里的类型 _class_t

struct _class_t {
struct _class_t *isa;
struct _class_t *superclass;
void *cache;
void *vtable;
struct _class_ro_t *ro;
};

这就是后面我们要继续探索的类的结构了。

其实还有别的如:_category_t_protocol_t 等。

回到我们今天的正题:对象的结构。

对象结构体

我们继续搜索 SMBook

#ifndef _REWRITER_typedef_SMBook
#define _REWRITER_typedef_SMBook
typedef struct objc_object SMBook;
typedef struct {} _objc_exc_SMBook;
#endif

extern "C" unsigned long OBJC_IVAR_$_SMBook$_name;
struct SMBook_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSString *_author;
NSString *_name;
};
  • NSObject_IVARS 继承自 NSObject 的属性:

    #ifndef _REWRITER_typedef_NSObject
    #define _REWRITER_typedef_NSObject
    typedef struct objc_object NSObject;
    typedef struct {} _objc_exc_NSObject;
    #endif

    struct NSObject_IMPL {
    Class isa;
    };
  • 对象自己的属性:

    • 属性的 getter 方法:

      static NSString * _I_SMBook_name(SMBook * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_SMBook$_name)); }
    • 属性的 setter 方法:

      static void _I_SMBook_setName_(SMBook * self, SEL _cmd, NSString *name) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct SMBook, _name), (id)name, 0, 1); }

    从上面两个方法中观察到两个参数:

    • self
    • _cmd
  • 实例方法:

    static void _I_SMBook_sayHello(SMBook * self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_yb_37j_8lyx0g1_dtywfftgmc880000gn_T_main_7812b7_mi_0);
    }
  • 类方法:

    static void _C_SMBook_sell(Class self, SEL _cmd) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_yb_37j_8lyx0g1_dtywfftgmc880000gn_T_main_7812b7_mi_1);
    }

这就是我们在开发过程中两个隐藏参数,在方法调用的过程中个,这两个参数不需要用户传递。

object_struct.png

对象实现

我们继续往下看:

  • 变量列表

    static struct /*_ivar_list_t*/ {
    unsigned int entsize; // sizeof(struct _prop_t)
    unsigned int count;
    struct _ivar_t ivar_list[2];
    } _OBJC_$_INSTANCE_VARIABLES_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_ivar_t),
    2,
    {{(unsigned long int *)&OBJC_IVAR_$_SMBook$_author, "_author", "@\"NSString\"", 3, 8},
    {(unsigned long int *)&OBJC_IVAR_$_SMBook$_name, "_name", "@\"NSString\"", 3, 8}}
    };

    这里有两个变量:

    • _author
    • _name
  • 实例方法列表:

    static struct /*_method_list_t*/ {
    unsigned int entsize; // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[3];
    } _OBJC_$_INSTANCE_METHODS_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    3,
    {{(struct objc_selector *)"sayHello", "v16@0:8", (void *)_I_SMBook_sayHello},
    {(struct objc_selector *)"name", "@16@0:8", (void *)_I_SMBook_name},
    {(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_SMBook_setName_}}
    };

    三个实例方法:

    • - sayHello
    • 属性方法:
      • name
      • setName
  • 类方法列表:

    static struct /*_method_list_t*/ {
    unsigned int entsize; // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[1];
    } _OBJC_$_CLASS_METHODS_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    1,
    {{(struct objc_selector *)"sell", "v16@0:8", (void *)_C_SMBook_sell}}
    };

    类方法:sell

  • 属性列表:

    static struct /*_prop_list_t*/ {
    unsigned int entsize; // sizeof(struct _prop_t)
    unsigned int count_of_properties;
    struct _prop_t prop_list[1];
    } _OBJC_$_PROP_LIST_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_prop_t),
    1,
    {{"name","T@\"NSString\",C,N,V_name"}}
    };

    属性:+ name

  • 元类的 ro

    static struct _class_ro_t _OBJC_METACLASS_RO_$_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    1, sizeof(struct _class_t), sizeof(struct _class_t),
    (unsigned int)0,
    0,
    "SMBook",
    (const struct _method_list_t *)&_OBJC_$_CLASS_METHODS_SMBook,
    0,
    0,
    0,
    0,
    };
  • 类的 ro

    static struct _class_ro_t _OBJC_CLASS_RO_$_SMBook __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    0, __OFFSETOFIVAR__(struct SMBook, _author), sizeof(struct SMBook_IMPL),
    (unsigned int)0,
    0,
    "SMBook",
    (const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_SMBook,
    0,
    (const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_SMBook,
    0,
    (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_SMBook,
    };

从这几个里面发现:

  • 对象的成员变量会进变量列表
  • 对象的属性会进变量列表和属性列表,同时创建 gettersetter 方法
  • 实例方法进实例方法列表
  • 变量列表、属性列表和方法列表都会放到类的 ro
  • 类方法进类方法列表
  • 类方法列表放在元类的 ro

对象的本质

对象的本质.png

clang 的两条命令:

  • 普通的 .m 文件:

    clang -rewrite-objc main.m -o main.cpp
  • 当文件内引用了动态库如 UIKit.m 文件:

    clang -x objective-c -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m

实例创建与方法调用

int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
SMBook *book = ((SMBook *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("SMBook"), sel_registerName("alloc"));
((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)book, sel_registerName("setName:"), (NSString *)&__NSConstantStringImpl__var_folders_yb_37j_8lyx0g1_dtywfftgmc880000gn_T_main_7b3826_mi_2);
}
return 0;
}

方法的调用通过 objc_msgSend 实现。