ObjC class ids and compiler magic?

Consider:

@interface Foo : NSObject + (void) dump ; @end @implementation Foo + (Class) classOf1 { return self ; } + (Class) classOf2 { return [Foo class] ; } + (Class) classOf3 { return [[[Foo class] new] class] ; } + (Class) classOf4 { return [[self new] class] ; } + (Class) classOf5 { return [[[self alloc] init] class] ; } + (Class) classOf6 { return [[[Foo alloc] init] class] ; } + (Class) classOf7 { return [self class] ; } + (void) dump { NSLog(@"classOf1 %@<0x%08.8lx>", [self classOf1], (unsigned long)[[self classOf1] hash]) ; NSLog(@"classOf2 %@<0x%08.8lx>", [self classOf2], (unsigned long)[[self classOf2] hash]) ; NSLog(@"classOf3 %@<0x%08.8lx>", [self classOf3], (unsigned long)[[self classOf3] hash]) ; NSLog(@"classOf4 %@<0x%08.8lx>", [self classOf4], (unsigned long)[[self classOf4] hash]) ; NSLog(@"classOf5 %@<0x%08.8lx>", [self classOf5], (unsigned long)[[self classOf5] hash]) ; NSLog(@"classOf6 %@<0x%08.8lx>", [self classOf6], (unsigned long)[[self classOf6] hash]) ; NSLog(@"classOf7 %@<0x%08.8lx>", [self classOf7], (unsigned long)[[self classOf7] hash]) ; } @end 

And the conclusion:

  2013-07-04 03:20:20.404 WC[29862:c07] classOf1 Foo<0x0002a2e4> 2013-07-04 03:20:21.075 WC[29862:c07] classOf2 Foo<0x0002a2e4> 2013-07-04 03:20:21.628 WC[29862:c07] classOf3 Foo<0x0002a2e4> 2013-07-04 03:20:22.229 WC[29862:c07] classOf4 Foo<0x0002a2e4> 2013-07-04 03:20:22.805 WC[29862:c07] classOf5 Foo<0x0002a2e4> 2013-07-04 03:20:23.387 WC[29862:c07] classOf6 Foo<0x0002a2e4> 2013-07-04 03:20:25.235 WC[29862:c07] classOf7 Foo<0x0002a2e4> 

All 7 cases return the same value!

The most mysterious cases for me:

  • classOf1 and classOf7

in the last "I" is "Foo", which is a class. So what is class class?

  • classOf5 and classOf6

Obviously, "Foo" and "self" play the same role in this context. As in

  • classOf3 and classOf4

It seems to me that "Foo" is a little magic rabbit.

You can

 @class Foo ; 

So that

 @class self ; 

doesn't make sense.

In the lexer to runtime generator pipeline, I can understand when the bitstream changes from a bunch of characters to an identifier to a language-dependent semantic element. But it's hard for me to determine the exact nature of the identifiers of the ObjC class.

Is anyone

(This SO question seems unrelated)

+6
source share
2 answers

You can see the answer in NSObject implementation :

 + (Class)class { return self; } - (Class)class { return object_getClass(self); } 

Sending class object does not return its metaclass, just the class object itself.

If you want a metaclass object for some reason, you should use the object_getClass() execution function, for example:

 NSLog(@"%d", class_isMetaClass(object_getClass([NSString class]))); // Prints 1 

You can also get a metaclass for the class name objc_getMetaClass() .

+8
source
 + (Class) classOf1 { return self ; } 

self in a class method is a Class object of the current class, so here self is a class object for class Foo


 + (Class) classOf2 { return [Foo class] ; } 

and here is the class object for class Foo


 + (Class) classOf3 { return [[[Foo class] new] class] ; } 

this is the same as

 Class fooClass = [Foo class]; id fooInstance = [fooClass new]; return [fooInstance class]; 

which will again provide you with an object of class class Foo


 + (Class) classOf4 { return [[self new] class] ; } 

just like the previous one, just replace [Foo class] with self


 + (Class) classOf5 { return [[[self alloc] init] class] ; } 

just like the previous one, just replace [Foo new] with [[Foo alloc] init]


 + (Class) classOf6 { return [[[Foo alloc] init] class] ; } 

just like the previous one, just replace self with Foo


 + (Class) classOf7 { return [self class] ; } 

like the second, just replace Foo with self


The difference between using Foo and self in a class method is that when this method is called in a subclass, self will be replaced with a subclass. eg.

 @interface Bar : Foo @end Class barClass = [Bar classOf1]; // same as [Bar class] Class fooClass = [Bar classOf2]; // same as [Foo class] 

If you really want to get a class of a class (e.g. metaclass), you need to use the objc execution function from <objc/runtime.h>

 id metaClass = objc_getMetaClass("Foo"); 
+5
source

Source: https://habr.com/ru/post/948666/


All Articles