I’m interested in understanding the circumstances leading a developer to override +initialize or +load. Documentation makes it clear these methods are called for you by the Objective-C runtime, but that’s really all that is clear from the documentation of those methods. 🙂
My curiosity comes from looking at Apple’s example code – MVCNetworking. Their model class has a +(void) applicationStartup method. It does some housekeeping on the filesystem, reads NSDefaults, etc etc… and, after trying to grok NSObject’s class methods, it seems like this janitorial work might be okay to put into +load.
I did modify the MVCNetworking project, removing the call in App Delegate to +applicationStartup, and putting the housekeeping bits into +load… my computer didn’t catch fire, but that doesn’t mean it’s correct! I’m hoping to gain an understanding of any subtleties, gotchas, and whatnots around a custom setup method you have to call versus +load or +initialize.
For +load documentation says:
The load message is sent to classes and categories that are both
dynamically loaded and statically linked, but only if the newly loaded
class or category implements a method that can respond.
This sentence is kludgey and difficult to parse if you don’t know the precise meaning of all the words. Help!
-
What is meant by “both dynamically loaded and statically linked?” Can something be dynamically loaded AND statically linked, or are they mutually exclusive?
-
“…the newly loaded class or category implements a method that can respond” What method? Respond how?
As for +initialize, documentation says:
initialize it is invoked only once per class. If you want to perform
independent initialization for the class and for categories of the
class, you should implement load methods.
I take this to mean, “if your trying to setup the class… don’t use initialize.” Okay, fine. When or why would I override initialize then?
The
loadmessageThe runtime sends the
loadmessage to each class object, very soon after the class object is loaded in the process’s address space. For classes that are part of the program’s executable file, the runtime sends theloadmessage very early in the process’s lifetime. For classes that are in a shared (dynamically-loaded) library, the runtime sends the load message just after the shared library is loaded into the process’s address space.Furthermore, the runtime only sends
loadto a class object if that class object itself implements theloadmethod. Example:The runtime sends the
loadmessage to theSuperclassclass object. It does not send theloadmessage to theSubclassclass object, even thoughSubclassinherits the method fromSuperclass.The runtime sends the
loadmessage to a class object after it has sent theloadmessage to all of the class’s superclass objects (if those superclass objects implementload) and all of the class objects in shared libraries you link to. But you don’t know which other classes in your own executable have receivedloadyet.Every class that your process loads into its address space will receive a
loadmessage, if it implements theloadmethod, regardless of whether your process makes any other use of the class.You can see how the runtime looks up the
loadmethod as a special case in the_class_getLoadMethodofobjc-runtime-new.mm, and calls it directly fromcall_class_loadsinobjc-loadmethod.mm.The runtime also runs the
loadmethod of every category it loads, even if several categories on the same class implementload. This is unusual. Normally, if two categories define the same method on the same class, one of the methods will “win” and be used, and the other method will never be called.The
initializeMethodThe runtime calls the
initializemethod on a class object just before sending the first message (other thanloadorinitialize) to the class object or any instances of the class. This message is sent using the normal mechanism, so if your class doesn’t implementinitialize, but inherits from a class that does, then your class will use its superclass’sinitialize. The runtime will send theinitializeto all of a class’s superclasses first (if the superclasses haven’t already been sentinitialize).Example:
This program prints two lines of output:
Since the system sends the
initializemethod lazily, a class won’t receive the message unless your program actually sends messages to the class (or a subclass, or instances of the class or subclasses). And by the time you receiveinitialize, every class in your process should have already receivedload(if appropriate).The canonical way to implement
initializeis this:The point of this pattern is to avoid
Someclassre-initializing itself when it has a subclass that doesn’t implementinitialize.The runtime sends the
initializemessage in the_class_initializefunction inobjc-initialize.mm. You can see that it usesobjc_msgSendto send it, which is the normal message-sending function.Further reading
Check out Mike Ash’s Friday Q&A on this topic.