Why do we have to do [MyClass class] in Objective-C?
In Objective-C, you can invoke class methods with:
[MyClass aClassMethod];
开发者_如何学PythonAnd you can query an instance's kind with:
[someInstance isKindOfClass:[MyClass class]];
But, why do we need to do [MyClass class]
, and not simply provide MyClass
like this:
[someInstance isKindOfClass:MyClass];
Is there a reason that the compiler is fine with encountering MyClass
as a receiver (a pointer type) but not as an argument? Is it a limitation of parsing the language? Or perhaps a limitation of the compiler?
Ooooh... fun question. The answer is a c-ism.
Consider:
@interface MyClass : NSObject
@end
@implementation MyClass
@end
Now, say you have:
...
MyClass *m = nil;
...
In that context, the compiler sees MyClass
as a type definition. The *
says that the variable m
is a pointer to a hunk o' memory that contains one (or many -- don't forget your C pointer-fu) MyClass instances
.
In other words, MyClass
is a type.
But, in the context of something like:
[someInstance isKindOfClass: x ];
x
must be an rvalue or, in human terms, the value of an expression. A type, however, cannot be used as an rvalue.
That [MyClass class]
works is actually a bit of a hack, both in the language and the compiler in that the grammar specifically allows a type name to be the message receiver (to be the target of a method call).
And, as a matter of fact, you can do:
typedef MyClass Foo;
....
[MyClass class];
[Foo Class];
It'll all work. However, you can't do the following but the error message is illuminating:
[NSUInteger class];
error: ‘NSUInteger’ is not an Objective-C class name or alias
Now, why not special case it everywhere as a bare name?
That colludes type names and rvalues and you quickly end up having to swallow something like [foo isKindOfClass: (MyClass)];
while barfing on [foo isKindOfClass: (MyClass *)];
which then encroaches upon typecasting territory in a rather uncomfortable fashion.
Interesting.
In Objective-C, class name has two roles, as a data type and as a class object. As a data type name, you can do things like:
MyClass *anObject;
As a class object, the class name can stand for the class object only as a message receiver. And this is why you have to use
... isKindOfClass:[MyClass class] ...
However, I don't think this is the answer which can satisfy your need. To me, the answer is, "yes, what you want is plausible. But the spec says the other way".
Reference: The Objective-C Programming Language Page 32, section: "Class Names in Source Code".
@John and @ryanprayogo -- you are both fundamentally wrong. MyClass is a Class, which is also an object, but does not inherit from NSObject. Objective-C is kind of weird this way, but its actually brilliant when fully explained (See here). The answer here, though, is as @yehnan said, that a class name can be either a type name for declarators and casts, or as a receiver for messages. The implementation of [MyClass class]
returns self (which is, within the method, MyClass). Also as @yehnan said, the language could support passing it as an argument, although it simply doesn't.
My first glance answer is because [MyClass class] return a object of type Class, and MyClass doesn't inherit from Class...
@yehnan captures it well, but I'll expand on this a little. Yes, the compiler could be modified to automatically convert a class identifier into its applicable Class
in places where it is an argument rather than only when it is the target of a message. But there's not a lot of call for that kind of added complexity in the compiler (translated: slower, harder to detect coding errors). You shouldn't be calling things that return Class
very often. If you are, then your object model is broken. Class-checking should be the last, desperate approach after everything else has failed (most notably correct typing and then respondsToSelector:
). So for this kind of rare event, it doesn't make a lot of sense to complicate the compiler this way.
Because what the isKindOfClass
expects is a "class" and that's what get returned from invoking: [MyClass class]
I'm thinking that MyClass is actually a meta-class. You send it the class message to get the actual class (of type Class).
MyClass
is not of type Class
.
[MyClass class]
is of type Class
.
If you are familiar with Java, the concept is the same.
java.lang.String
is not of type java.lang.Class
java.lang.String.getClass()
is of type java.lang.Class
精彩评论