6

I get two different object instances when calling object_getClass(obj) and [obj class]. Any idea why?

Class cls = object_getClass(obj);
Class cls2 = [obj class];

(lldb) po cls
$0 = 0x0003ca00 Test
(lldb) po cls2
$1 = 0x0003ca14 Test
(lldb) 
Boon
  • 40,656
  • 60
  • 209
  • 315

2 Answers2

13

I suspect that obj, despite the name, is a class. Example:

Class obj = [NSObject class];
Class cls = object_getClass(obj);
Class cls2 = [obj class];
NSLog(@"%p",cls);  // 0x7fff75f56840
NSLog(@"%p",cls2); // 0x7fff75f56868

The reason is that the class of a Class object is the same class, but the object_getClass of a Class is the meta class (the class of the class). This makes sense because a Class is an instance of the meta class, and according to documentation object_getClass returns “The class object of which object is an instance”. The output in LLDB would be:

(lldb) p cls
(Class) $0 = NSObject
(lldb) p cls2
(Class) $1 = NSObject
(lldb) po cls
$2 = 0x01273bd4 NSObject
(lldb) po cls2
$3 = 0x01273bc0 NSObject

If you replace Class obj = [NSObject class]; with NSObject *obj = [NSObject new];, the result will be the same when printing cls and cls2. That is,

    NSObject *obj = [NSObject new];
    Class cls = object_getClass(obj);
    Class cls2 = [obj class];
    NSLog(@"%p",cls);  // 0x7fff75f56840
    NSLog(@"%p",cls2); // 0x7fff75f56840
Jano
  • 62,815
  • 21
  • 164
  • 192
  • nice explanation. Just a question: shouldn't the result of `object_getClass(obj)` be a pointer to the `Class` class? Why does the debugger print `NSObject`? – Gabriele Petronella Apr 09 '13 at 16:23
  • 2
    LLDB has custom formatters for specific types. If you type `type summary list` you'll get a list of them, at the top you see that Class is in category objc and it says (skip pointers). You can disable or enable the category, eg: `type category disable objc` then try again, you'll see the pointer, replace with enable to enable it again. Default categories are on disk somewhere, you can add your own. See http://lldb.llvm.org/varformats.html for details. – Jano Apr 09 '13 at 17:04
  • Thank you very much, that's a hell of explanation :) – Gabriele Petronella Apr 09 '13 at 17:07
  • @GabrielePetronella: Just to clarify, there is no "`Class` class". `Class` is just a C type, like `id`, rather than an actual class itself. You're possibly thinking of Ruby. In Objective-C, each class is the sole instance of a metaclass, which is kindasorta similar to Ruby's singleton classes. – Chuck Apr 09 '13 at 17:10
  • Thank you @Chuck. I'm familiar with the definition of `Class` as a pointer to the `objc_class` C struct, but what do you exactly mean by *metaclass*? – Gabriele Petronella Apr 09 '13 at 17:18
  • @GabrielePetronella: So, when you send a message to an object, the selector is looked up in the method table of that object's class, right? So when you send a message to a class object, where is that method looked up? The answer is: the same place as any other message send: in the object's class. In this case, it is the class's class, which is called a metaclass. They exist pretty much as a bag for class methods. – Chuck Apr 09 '13 at 17:30
  • @Chuck Ok so basically I have my obj instance, whose class is NSObject. NSObject is an struct of type objc_class responding to the class methods, correct? – Gabriele Petronella Apr 09 '13 at 17:57
  • @GabrielePetronella: Yep. If you look at the definition of the objc_class struct, it is a valid object (i.e. it starts with `id isa`). The `isa` pointer for a class struct points to the class's metaclass, so the runtime message resolution machinery doesn't have to do anything special for classes. – Chuck Apr 09 '13 at 18:38
  • What does cls2 in your example actually get us? Shouldn't [[NSObject class] class] get us the metaclass just like object_getClass([NSObject class]) does? – Boon Apr 09 '13 at 18:40
  • @Boon The +class of a Class is the same class. That is [NSObject class] == [[NSObject class] class] == [[[NSObject class] class] class]. If you print the pointers, they are all the same. – Jano Apr 09 '13 at 19:10
  • Here is some great stuff to read to help understanding this answer: http://www.cocoawithlove.com/2010/01/what-is-meta-class-in-objective-c.html – MANIAK_dobrii Mar 29 '14 at 17:57
3

The previous answer is right, but not the one for the asker.

For an instance(not a class), the only reason "object_getClass(obj)" and "[obj class]" get different is "isa-swizzling" or some other swizzling that changes the instance's 'isa' pointer.

When you add a 'KVO' to an instance, the instance is isa-swizzled. see Key-Value Observing Implementation Details

Some other libraries like ReactiveCocoa will also change an instance's 'isa' pointer. (Search 'RACSwizzleClass' in Source of ReactiveCocoa)

See also this blog(in Chinese):Class-swizzling, Isa-swizzling and KVO

Dongle
  • 31
  • 4