The category on NSObject is also working on the class.

So, I have a category in NSObject called CustomCategory, as shown below:

#import <Foundation/Foundation.h> @interface NSObject (CustomCategory) -(BOOL)doSomething; @end #import "NSObject+CustomCategory.h" @implementation NSObject (CustomCategory) -(BOOL)doSomething { NSLog(@"Done"); return NO; } @end 

Ideally, this will work on such an object:

 NSObject* object = [NSObject new]; [object doSomething]; 

However, I found that it also works this way without problems:

 [NSObject doSomething]; 

So I'm interested, since this is an instance method that I added through the category, why does it also work in the class?

+5
source share
3 answers

Instance methods in NSObject are also class methods in NSObject.

This works because of the way Objective-C performs dynamic dispatch. If you send a message to any object, the implementation of the method is viewed in the class of objects. If you send a message to a class, you send a regular message to the class object. There, the implementation is viewed in the so-called metaclass. Meta classes are automatically generated by the compiler. Class methods are just the methods of the metaclass instance. This is handled transparently by the compiler.

Inheritance also works at the metaclass level. Thus, the metaclass for a class is inherited from the metaclass of its superclass. We have two parallel inheritance hierarchies. Only root classes, such as NSObject, are handled differently. There, the metaclass cannot inherit from the metaclass of the superclass, since there is no superclass. For root classes, the meta class is inherited from the root class itself.

And since class class methods are instances of metaclass metaclass methods and NSObjects metaclasses that inherit from NSObject methods themselves, instance methods in NSObject are also class methods in NSObject.

+3
source

To link to anyone looking for the actual location of this in the runtime source, it is currently located in objc-runtime-new.mm methodizeClass :

 ... snip... // Root classes get bonus method implementations if they don't have // them already. These apply before category replacements. if (cls->isRootMetaclass()) { // root metaclass addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO); } ... snip ... 

... And the +initialize method of the metaclass will add all the method implementations from its instance and convert them to a class method.

And, contrary to what @Sven said, the metaclass NSObject is not really NSObject. A class always has a separate metaclass in the runtime, regardless of whether it is a root or not.

+3
source

Each Class in Objective-C is an internal object, which means its subclass is NSObject .

-2
source

All Articles