OC对象的分类和本质

172 阅读2分钟

OC对象的底层实现

将.m文件转换为.cpp文件

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o 输出的CPP文件

参数解释

-sdk 指定平台

-arch 指定架构

-o 指定输出文件

main.m 为编写的OC源文件

main.cpp 为编译后的C++目标文件

消息机制

在main.cpp中的最后找到我们的main方法和创建NSObject对象的语句

int main(int argc, char * argv[]) {
    { __AtAutoreleasePool __autoreleasepool;
        NSObject * obj = objc_msgSend(objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
    }
    return 0;
}

NSObject * obj = [[NSObject alloc] init];

分为两步执行

第一步

NSObject * obj = [NSObject alloc];

NSObject * obj = objc_msgSend(objc_msgSend(objc_getClass("NSObject"), sel_registerName("alloc"))

通过函数objc_msgSend向NSObject这个类发送alloc消息, 返回一个对象

第二步

obj = [obj init];

obj = objc_msgSend(obj, sel_registerName("init"));

通过函数objc_msgSend向[NSObject alloc]创建的对象发送init消息, 返回一个初始化好的对象

OC中类的底层实现

// OC代码
@interface NSObject {
    Class isa;
}

// 底层实现
struct NSObject_IMPL {
	Class isa;
};

// Class
typedef struct objc_class *Class;

// objc_class
struct objc_class : objc_object {
  // ...
}

// objc_object
struct objc_object {
	Class ISA();
  // ...
}

OC中的类是通过C++的结构体来实现的

自定义类CLPerson

// 源代码
@interface CLPerson : NSObject
{
    NSInteger no;
    NSInteger age;
}
@end

// 底层实现
struct CLPerson_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	NSInteger no;
	NSInteger age;
};

/**
NSObject_IMPL这个结构体只有一个Class isa; 
所以CLPerson的底层实现相当于下面这样
*/
struct CLPerson_IMPL {
	Class isa;
	NSInteger no;
	NSInteger age;
};

通过结构体指针改变对象成员变量的值

让结构体指针指向对象, 通过结体指针修改所所指对象成员变量的no, age的值

CLPerson * p = [[CLPerson alloc] init];
p -> no = 1001;
p -> age = 16;
printf("p - no: %ld, p - age: %ld \n", p -> no, p -> age);

struct CLPerson_IMPL * p2 = (__bridge struct CLPerson_IMPL *)p;

p2 -> no = 2002;
p2 -> age = 18;

printf("p - no: %ld, p - age: %ld \n", p -> no, p -> age);

OC对象的分类

NSObject * obj1 = [[NSObject alloc] init];
NSObject * obj2 = [[NSObject alloc] init];
printf("实例对象: %p, %p \n", obj1, obj2);

Class cls1 = [obj1 class];
Class cls2 = [obj2 class];
Class cls3 = object_getClass(obj1);
Class cls4 = object_getClass(obj2);
printf("类对象: %p, %p, %p, %p \n", cls1, cls2, cls3, cls4);

Class mCls = object_getClass([NSObject class]);
printf("元类对象: %p \n", mCls);
实例对象: 0x283038120, 0x283038110 
类对象: 0x1ed193218, 0x1ed193218, 0x1ed193218, 0x1ed193218 
元类对象: 0x1ed1931f0 

instance对象 / 实例对象

obj1, obj2是两个不同的实例对象, 有着不同的内存

内存中的信息主要包括

主要包括

  • isa指针
  • 其它成员变量

class对象 / 类对象

cls1, cls2, cls3, cls4是同一个类对象, 有着同一块内存, 有且只有一个

内存中的信息主要包括

  • isa指针
  • superclass指针
  • 成员变量信息
  • 属性信息
  • 对象方法信息
  • 协议信息

meta-class对象 / 元类对象

mCls是一个元类对象, 在内存中有且只有一个

内存中的信息主要包括

  • isa指针
  • superclass指针
  • 类方法信息