When and who called +initialize? - objective-c

My program has a class and that class has an +initialize method. I wonder who calls that method? The debugging tools are very unclear:
What triggers +initialize to be called? The beginning of application launch?

The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program.
See the documentation for + (void)initialize on NSObject.
An authoritative blog post on the question of initialize states that initialize is executed once when the class is first used, i.e. as the docs state before the class is sent its first message.

Related

Why does registering a subclass with its superclass in +initialize present a chicken and egg issue? (objc)

Just reading an excerpt from this website.
Because +initialize runs lazily, it's obviously not a good place to
put code to register a class that otherwise wouldn't get used. For
example, NSValueTransformer or NSURLProtocol subclasses can't use
+initialize to register themselves with their superclasses, because you set up a chicken-and-egg situation.
I understand that +initialize is run once per class when the first message is sent to that class. Also, if any of the subclasses do not implement their own +initialize, the +initialize method will be run again in the superclass.
I am just not 100% on why registering a subclass with its superclass in its own +initialize method would present a chicken and egg problem.
Is it because the superclass may have never had its +initialize invoked, and you are trying to register your subclass with its superclass in a method that depends on the superclass calling its +initialize first?
Just a little bit of further clarification would go a long way for me, thank you.
Take the example of NSURLProtocol. The way it's used is that registered subclasses are asked, in turn, if they can handle a request. The first to answer yes gets an instance created and the request is handed off.
The initialize method is only called if a message is sent to the class. Since only registered subclasses are asked to handle a request, you can't register in initialize because it won't ever be invoked.
Two extracts from the documentation on the initialize method:
The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program. The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses.
...
Because initialize is called in a thread-safe manner and the order of initialize being called on different classes is not guaranteed, it’s important to do the minimum amount of work necessary in initialize methods. Specifically, any code that takes locks that might be required by other classes in their initialize methods is liable to lead to deadlocks. Therefore you should not rely on initialize for complex initialization, and should instead limit it to straightforward, class local initialization.
The initialize message is sent to a class the first time the runtime encounters it, for example the first time you need to allocate that class or the first time you access its sharedInstance method (in case of a singleton), and it acquires some locks in order to guarantee the thread safety. If you make references to subclasses from within this method, you can get into a deadlock situation, as both the base class and the subclass will lock onto the same thing.
For example, let's consider the scenario of a superclass MyClass and one of it's children MySubclass:
#interface MyClass
#end
#interface MySubclass: MyClass
#end
#implementation MyClass
+ (void)initialize {
[MySubclass doSomething];
}
When the runtime encounters the first usage of MyClass, it acquires a lock, and calls the class method initialize. Now, when executing the method it realises that this is also the first time it encounters MySubclass, and must also intialize it before the class can do some actual work. And what does this trigger? Yes, you've guessed, another call to +[MyClass initialize].
This how we end up in the chicken-egg situation, or to put it more technical - the deadlock, or the recursion. MyClass calls on MySubclass, this means that MySubclass needs to be initialized before MyClass is used. However MySubclass is a child of MyClass, so MyClass should be initialized first. So, which one the two should be first initialized?

Signal for a class method in ReactiveCocoa

I'd like to create a RACSignal whenever particular class methods are called. This is easy to do for instance methods (rac_signalForSelector) but I can't find a way to do it with class methods. e.g. I'd like to receive a signal on NSError's errorWithDomain:code:userInfo: and see what parameters it was created with. But really it should be a general solution so I can see when any class method is called. Access to the resulting instance is optional.

Why is -init an instance method and +initialize a class method? [duplicate]

This question already has an answer here:
Why is init not a class method?
(1 answer)
Closed 8 years ago.
In Cocoa, for NSObjects, shouldn't both init and initialize be class methods?
+initialize can be overridden (it's optional) to perform class-wide initialization.
-init performs initialization of a single instance of a class, though it's often refined by adding arguments in classes derived from NSObject (ex: UIView's initWithFrame: method).
Since -init initializes a single instance (in particular, it has access to the instance's variables), it can't be a class method.
From the docs:
The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program.
This means that the first time you send a message to the class, whether it be alloc or some defined class method, initialize is called first, once, for the entire run of the application. As opposed to load, it is possible to include a class in a project and never hit initialize.
init, on the other hand, is
Implemented by subclasses to initialize a new object (the receiver) immediately after memory for it has been allocated.
Meaning, init is sheerly used for initializing class instances.
Edit --
Following the edited question, alloc creates the instance while init initializes it, which is why alloc is a class method and init is an instance method.

Class and instance methods with the same name

I'm looking at Apple's MVC Networking sample project and I have found that in the class PhotoGallery the author has created instance and class versions of the method abandonGalleryCacheAtPath::
On line 139:
+ (void)abandonGalleryCacheAtPath:(NSString *)galleryCachePath
On line 457:
- (void)abandonGalleryCacheAtPath:(NSString *)galleryCachePath
All the instance version of the method seems to do is a bit of logging before calling the class method as follows:
[[QLog log] logWithFormat:#"gallery %zu abandon '%#'", (size_t) self.sequenceNumber, [galleryCachePath lastPathComponent]];
[[self class] abandonGalleryCacheAtPath:galleryCachePath];
The log message includes self.sequenceNumber, which is an instance variable which would not be available to the class method.
A couple of questions:
Will the system automatically direct calls to the right method e.g. if another class method calls self abandonGalleryCacheAtPath:abc then the class version of the method will be executed, and if another instance method calls it then the instance version of the method will be executed?
Do you think the author has implemented the instance method purely so that the value of sequenceNumber can be logged? Are there any other design/technical benefits of doing this kind of double implementation?
Since Objective C uses dynamic method binding, the system will automatically direct calls to the Class or Instance method depending on the context in which the call was made. Refer Objective-C uses dynamic binding, but how?

Objective C message dispatch mechanism [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 months ago.
The community reviewed whether to reopen this question 7 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
I am just staring to play around with Objective C (writing toy iPhone apps) and I am curious about the underlying mechanism used to dispatch messages. I have a good understanding of how virtual functions in C++ are generally implemented and what the costs are relative to a static or non-virtual method call, but I don't have any background with Obj-C to know how messages are sent. Browsing around I found this loose benchmark and it mentions IMP cached messages being faster than virtual function calls, which are in turn faster than a standard message send.
I am not trying to optimize anything, just get deeper understanding of how exactly the messages get dispatched.
How are Obj-C messages dispatched?
How do Instance Method Pointers get cached and can you (in general) tell by reading the code if a message will get cached?
Are class methods essentially the same as a C function (or static class method in C++), or is there something more to them?
I know some of these questions may be 'implementation dependent' but there is only one implementation that really counts.
How are Obj-C messages dispatched?
Objective-C messages are dispatched using the runtime's objc_msgSend() function. Shown in the Apple docs, the function takes at least 2 arguments:
The receiving object
The selector of the message
[A variable list of arguments to the message being sent.]
Instances of a class have an isa pointer, which is a pointer to their class object. The selectors of methods in each object are stored in a "table" in the class object, and the objc_msgSend() function follows the isa pointer to the class object, to the find this table, and checks whether the method is in the table for the class. If it cannot find it, it looks for the method in the table of the class's superclass. If not found, it continues up the object tree, until it either finds the method or gets to the root object (NSObject). At this point, an exception is thrown.
How do Instance Method Pointers get cached and can you (in general) tell by reading the code if a message will get cached?
From Apple's Objective-C runtime guide on Messaging:
To speed the messaging process, the runtime system caches the selectors and addresses of methods as they are used. There’s a separate cache for each class, and it can contain selectors for inherited methods as well as for methods defined in the class. Before searching the dispatch tables, the messaging routine first checks the cache of the receiving object’s class (on the theory that a method that was used once may likely be used again). If the method selector is in the cache, messaging is only slightly slower than a function call. Once a program has been running long enough to “warm up” its caches, almost all the messages it sends find a cached method. Caches grow dynamically to accommodate new messages as the program runs.
As stated, caching starts to occur once the program is running, and after the program has been running long enough, most of the method calls will run through the cached method. As it also says, the caching occurs as the methods are used, so a message is only cached when it is used.
Are class methods essentially the same as a C function (or static class method in C++), or is there something more to them?
Class objects handle method despatch in a similar manner to that of instances of classes. Each class object has an object that stores its own class methods, in an object called a metaclass. The class object has its own isa pointer to its metaclass object, which in turn has super metaclass objects, which it can inherit class objects from. Method dispatch to class methods is as so:
The dispatch system follows the class object's isa pointer to the metaclass object
The metaclass object's method table is searched for the class method.
If not found, the search continues to the metaclass object's superclass, where the search continues.
This process repeats until either the method is found, or until it gets to the root metaclass, and an exception is thrown.
Dispatch mechanisms
It is used to find a necessary executable code when method was called(message sent)
Inline
Static(Direct)(C, Java final, C++ default, Swift static, final) - compiler knows the necessary method realisation at compile-time.
Dynamic - is based on witness table(virtual table, dispatch table) and it introduce polymorphism
Table, V-Table(C++ virtual, Java default, Swift default) - Every object has a reference to class which has a table with all method addresses(super, overrides, new). SIL contains vtable or witness_table
Message(Objective-C, Swift dynamic) - Every object has a reference(isa) to class which contains a reference to superclass and dispatch table(which contains only realised methods(new and which were overhead)) and don't contain methods from super. If method was not found in current dispatch table, it continue searching in superclass's dispatch table. This process is optimised by caching. SIL contains volatile
Objective-C Message Dispatch
For example
class A {
func foo1() {}
func foo2() {}
}
class B: A {
override func foo2() {}
func foo3() {}
}
Objective-C obc_msgSend
id obc_msgSend(id self, SEL op, ...)
// self - object which receive a message
// op - selector of method
//... - arguments
If method implementation was not found for given selector you see next error
unrecognized selector sent to instance