Objective-C 类与实例调用 self 方法的区分

Objective-C 类与实例调用 self 方法的区分

声明一个 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]

运行时的相关方法可以参考 iOS 运行时方法列表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值