Reputation: 123
This is my sample code:
View *v1 = [View new];
NSLog(@"%d",([v1 isKindOfClass:[View class]]));
NSLog(@"%d",([[v1 class] isKindOfClass:[View class]]));
View
is a class, now I have some confusion:
[v1 class]
is an pointer named isa
point to class object, right?[View class]
is an pointer named isa
point to meta class, right?I log address of [v1 class]
and [View class]
, they are equal, why?
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
I guess the key point is the return value of [View class]
, so if the return value of [View class]
does not point to its meta class, who is it ?? who is it point to ??
Edit
I got some informations from apple document, type method of -class and instance method of class, the two method have same return value, named class object
, what's this ? the instance of meta class ?? and how to get metaclass ?
Upvotes: 0
Views: 84
Reputation: 385580
- v1 is an instance of View, and View is an instance of View's meta class, right?
v1
is an instance of View
.
You cannot use View
as a regular C identifier, only as the recipient of class messages (like [View new]
), but there is a real object that receives those class messages. It's common and convenient to call that the View
class object, and it is the only instance of the View
metaclass.
- return value of
[v1 class]
is an pointer namedisa
point to class object, right?
[v1 class]
returns a reference to the View
class object. The isa
“pointer” is an implementation detail and in fact its implementation has changed. See “Non-pointer isa”.
- return value of
[View class]
is an pointer namedisa
point to meta class, right?
[View class]
means exactly the same thing as [View self]
. Both return the View
class object, not a metaclass object. You can see this in the Objective-C runtime source code. I will quote the relevant method definitions here.
+ (id)self {
return (id)self;
}
When you say [View self]
, it runs the +[NSObject self]
method quoted above, with the local variable self
pointing to the View
class object. (Whew, that's a lot of “self”!) So [View self]
returns the View
class object:
- (id)self {
return self;
}
When you say [v1 self]
, it runs the -[NSObject self]
method quoted above, with the local variable self
pointing to the v1
object (a View
instance). So [v1 self]
returns v1
.
+ (Class)class {
return self;
}
When you say [View class]
, it runs the +[NSObject class]
method quoted above, with the local variable self
pointing to the View
class object. So [View class]
returns the View
class object, just like [View self]
does.
- (Class)class {
return object_getClass(self);
}
When you say [v1 class]
, it runs the -[NSObject class]
method quoted above, with the local variable self
pointing to the v1
object (a View
instance). This method has a different body than the three other methods above. This method uses the Objective-C runtime function object_getClass
to get a reference to the View
class object.
I log address of [v1 class] and [View class], they are equal, why?
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
As I explained above, both of these return the View
class object.
- I guess the key point is the return value of [View class], so if the return value of [View class] does not point to its meta class, who is it ?? who is it point to ??
[View class]
returns the same thing as [View self]
: the View
class object. If you want to get a reference to the View
metaclass object, you need to use the Objective-C runtime directly, like this:
NSLog(@"%p", object_getClass([View class]));
Note that if you print [View class]
with %@
, it just prints View
. And if you print object_getClass([View class])
with %@
, it also just prints View
. You cannot distinguish between the View
class object and the View
metaclass object by their string descriptions. You have to look at the pointer values (which is indeed what you were doing).
Here is my test:
#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;
}
Here is the output (with NSLog
fluff removed):
v1 = <View: 0x101600780> / 0x101600780
[v1 class] = View / 0x1000011e0
[[v1 class] class] = View / 0x1000011e0
[View class] = View / 0x1000011e0
object_getClass([View class]) = View / 0x1000011b8
So:
v1
object is at 0x101600780,View
class object is at 0x1000011e0,View
metaclass object is at 0x1000011b8.You might wonder why [View class]
returns the View
class object instead of the View
metaclass object. Greg Parker is the main Apple employee who maintains the Objective-C runtime, and he explains why in a blog post titled “Classes and metaclasses”:
Objective-C uses metaclasses for practical goals like class methods, but otherwise tends to hide metaclasses. For example,
[NSObject class]
is identical to[NSObject self]
, even though in formal terms it ought to return the metaclass thatNSObject->isa
points to. The Objective-C language is a set of practical compromises; here it limits the class schema before it gets too, well, meta.
Upvotes: 2