本文共 2524 字,大约阅读时间需要 8 分钟。
声明一个 Person
类,考虑如下代码:
id aa = [Person self];id bb = [self self];Person *cc = self;id dd = [cc self];
我们知道在 <NSObject>
协议中声明有实例方法:- (instancetype)self;
,但是并没有 self
类方法。
那么调用类方法 self
为什么不会出错,将上面的代码转为 C 语言,如下:
id aa = ((id (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("self"));id bb = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("self"));Person *cc = self;id dd = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)cc, sel_registerName("self"));
可见,类方法 self
的调用,实际是向 Class 类对象发送了一个 self
消息,使用下面的方法,获取 self
方法在实例与类中的实现。
Method method1 = class_getClassMethod(object_getClass(Person.class), @selector(self));IMP imp1 = method_getImplementation(method1); Method method2 = class_getClassMethod(object_getClass(self.class), @selector(self));IMP imp2 = method_getImplementation(method2); Method method3 = class_getClassMethod(object_getClass(self), @selector(self));IMP imp3 = method_getImplementation(method3);
使用 po
命令,打印得到的结果均如下:
(libobjc.A.dylib`+[NSObject self])
Method method1 = class_getInstanceMethod(object_getClass(Person.class), @selector(self));IMP imp1 = method_getImplementation(method1); Method method2 = class_getInstanceMethod(object_getClass(self.class), @selector(self));IMP imp2 = method_getImplementation(method2); Method method3 = class_getInstanceMethod(object_getClass(self), @selector(self));IMP imp3 = method_getImplementation(method3);
使用 po
命令,打印得到的结果均如下:
(lldb) po imp1(libobjc.A.dylib`+[NSObject self])(lldb) po imp2(libobjc.A.dylib`+[NSObject self])(lldb) po imp3(libobjc.A.dylib`-[NSObject self])
从上面的结果来看,就明白为何将类对象称为元类的实例了。
self.class、Person.class、object_getClass(self) 获取的都是描述 Person 类的 Class 类对象,
其中包含了实例所包含的属性及方法。而 object_getClass(self.class)、object_getClass(Person.class) 得到的是描述 Class 类对象的 Class 元类对象,
其中包含了类属性及类方法。换言之,get_getClass() 函数总是获取参数的描述对象,而 class 方法,则只是返回调用者的类对象。
去 NSObject 中查找 self
方法,如下:
[self printClassMethod:object_getClass(NSObject.class)]; NSObject *object = [[NSObject alloc]init];[self printClassMethod:object_getClass(object)];- (void)printClassMethod:(Class)class { unsigned int count; Method *list = class_copyMethodList(class, &count); NSLog(@"===count : %d===",count); for (int i = 0; i < count; i++) { SEL name = method_getName(*(list+i)); NSLog(@"%s",sel_getName(name)); }}
此次测试打印的数量如下:
===count : 114======count : 355===
最终结果显示,NSObject 中是存在类方法 self
的,这也是 [Person self]
能够编译执行的原因。
实际 [Person self]
等同于 [Person class]
。
运行时的相关方法可以参考 。
转载地址:http://ovdws.baihongyu.com/