这是我的示例代码:
View *v1 = [View new];
NSLog(@"%d",([v1 isKindOfClass:[View class]]));
NSLog(@"%d",([[v1 class] isKindOfClass:[View class]]));
View
是一个班级,现在我有些困惑:
[v1 class]
的返回值是一个名为isa
的指针指向类对象,对吗?[View class]
的返回值是一个名为isa
的指针指向元类,对吗?我记录[v1 class]
和[View class]
的地址,它们是相同的,为什么?
NSLog(@"%p", [v1 class]);
NSLog(@"%p", [View class]);
2018-01-05 10:47:30.554190+0800 Block[16532:785147] 0x10a61a178
2018-01-05 10:47:30.554300+0800 Block[16532:785147] 0x10a61a178
我猜关键点是[View class]
的返回值,所以如果[View class]
的返回值没有指向它的元类,那么它是谁?谁指出??
修改
我从apple文档type method of -class和instance method of class获得了一些信息,这两个方法具有相同的返回值,名为class object
,这是什么?元类的实例??以及如何获得元类?
答案 0 :(得分:2)
- v1是View的一个实例,View是View的元类的一个实例,对吗?
醇>
v1
是View
的实例。
您不能将View
用作常规C标识符,仅作为类消息的接收者(如[View new]
),但有一个真实对象接收这些类消息。调用View
类对象是常见且方便的,它是View
元类的唯一实例。
- 醇>
[v1 class]
的返回值是一个名为isa
的指针指向类对象,对吗?
[v1 class]
返回对View
类对象的引用。 isa
“指针”是一个实现细节,实际上它的实现已经改变。请参阅“Non-pointer isa”。
- 醇>
[View class]
的返回值是一个名为isa
的指针指向元类,对吗?
[View class]
与[View self]
完全相同。两者都返回View
类对象,而不是元类对象。您可以在the Objective-C runtime source code中看到此信息。我将在这里引用相关的方法定义。
+ (id)self {
return (id)self;
}
当您说[View self]
时,它会运行上面引用的+[NSObject self]
方法,局部变量self
指向View
类对象。 (哇,那很多“自我”!)所以[View self]
返回View
类对象:
- (id)self {
return self;
}
当您说[v1 self]
时,它会运行上面引用的-[NSObject self]
方法,局部变量self
指向v1
对象(View
个实例)。因此[v1 self]
会返回v1
。
+ (Class)class {
return self;
}
当您说[View class]
时,它会运行上面引用的+[NSObject class]
方法,局部变量self
指向View
类对象。因此,[View class]
会返回View
类对象,就像[View self]
那样。
- (Class)class {
return object_getClass(self);
}
当您说[v1 class]
时,它会运行上面引用的-[NSObject class]
方法,局部变量self
指向v1
对象(View
个实例)。该方法与上述其他三种方法具有不同的主体。此方法使用Objective-C运行时函数object_getClass
来获取对View
类对象的引用。
- 醇>
我记录[v1 class]和[View class]的地址,它们是相同的,为什么?
NSLog(@"%p", [v1 class]); NSLog(@"%p", [View class]); 2018-01-05 10:47:30.554190+0800 Block[16532:785147] 0x10a61a178 2018-01-05 10:47:30.554300+0800 Block[16532:785147] 0x10a61a178
如上所述,这两个都返回View
类对象。
- 我猜关键点是[View class]的返回值,所以如果[View class]的返回值没有指向它的元类,那么它是谁?是谁指向??
醇>
[View class]
返回与[View self]
相同的内容:View
类对象。如果要获取对View
元类对象的引用,则需要直接使用Objective-C运行时,如下所示:
NSLog(@"%p", object_getClass([View class]));
请注意,如果您使用[View class]
打印%@
,则只会打印View
。如果您使用object_getClass([View class])
打印%@
,它也会打印View
。您无法通过字符串描述区分View
类对象和View
元类对象。你必须查看指针值(这确实是你在做什么)。
这是我的测试:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@interface View: NSObject
@end
@implementation View
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
View *v1 = [View new];
NSLog(@"v1 = %@ / %p", v1, v1);
NSLog(@"[v1 class] = %@ / %p", [v1 class], [v1 class]);
NSLog(@"[[v1 class] class] = %@ / %p", [[v1 class] class], [[v1 class] class]);
NSLog(@"[View class] = %@ / %p", [View class], [View class]);
NSLog(@"object_getClass([View class]) = %@ / %p", object_getClass([View class]), object_getClass([View class]));
}
return 0;
}
这是输出(删除了NSLog
绒毛):
v1 = <View: 0x101600780> / 0x101600780
[v1 class] = View / 0x1000011e0
[[v1 class] class] = View / 0x1000011e0
[View class] = View / 0x1000011e0
object_getClass([View class]) = View / 0x1000011b8
所以:
v1
对象位于0x101600780,View
类对象位于0x1000011e0,View
元类对象位于0x1000011b8。您可能想知道为什么 [View class]
返回View
类对象而不是View
元类对象。 Greg Parker是维护Objective-C运行时的主要Apple员工,他在a blog post titled “Classes and metaclasses”中解释了原因:
Objective-C使用元类来实现像类方法这样的实际目标,但是否则会隐藏元类。例如,
[NSObject class]
与[NSObject self]
相同,即使在正式术语中它应该返回NSObject->isa
指向的元类。 Objective-C语言是一套实际的妥协;在这里它限制了类模式,然后, meta 。