In Objective-C, what gets called before main? For example, I assume all metaclasses in Objective-C get instantiated before main and their load/initialize methods called, global constants, etc. What else? Is this documented anywhere?
A +load method which is part of any class in your application (not in any loaded framework) will be executed before main(). The full order of execution is given in the +load documentation (NSObject class reference):
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.
The order of initialization is as follows:
• All initializers in any framework you link to.
• All +load methods in your image.
• All C++ static initializers and C/C++ __attribute__(constructor) functions in your image.
• All initializers in frameworks that link to you.
In addition:
• A class’s +load method is called after all of its superclasses’ +load methods.
• A category +load method is called after the class’s own +load method.
In a custom implementation of load you can therefore safely message other unrelated classes from the same image, but any load methods implemented by those classes may not have run yet.
So if you add a +load to, say, your app delegate class it will run before main().
HTH
Related
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//do my job
});
}
I just wonder if a class with +load function just call once before main, so why need write dispatch_once inside?
I just wonder if a class with +load function just call once before main,
A +load method is not called "once before main" though that might be the common case, it is called once by the runtime after the image it is part of is loaded and with dynamically loaded images (see Initializing Objective-C Classes in Apple's Dynamic Library Programming Topics) that might be after main – see the +load documentation.
so why need write dispatch_once inside?
If your code never directly calls +load then there seems to be no need, though there is no explicit discussion of thread safety in the Dynamic Library Programming Topics or in +load's documentation as with the +initialize method.
However +load is just a method and can be called directly though it would unusual to do so, so maybe the writer just used dispatch_once out of an abundance of caution but we can't really know.
(Note: +initialize method can be called more than once by the runtime due to inheritance. However as +initialize is thread-safe a simple test can be used to ensure code is only run once, there is no need to use dispatch_once.)
HTH
Lets imagine that we have two classes:
#interface First : NSObject
#end
#interface Second : NSObject
#end
#implementation First
+(void)load
{
NSLog(#"This must be called first");
}
#end
#implementation Second
+(void)load
{
NSLog(#"And this must be called second");
}
#end
We have +load methods in each class. If we run this code, This must be called first will be first and And this must be called second will be second.
What determines the order in which the +load methods of this classes are called? In my experiment, if I move #implementation of second class before #implementation of first class - And this must be called second is printed first and This must be called first is printed second. Is this means that +load order depends only from order in source code?
In my real case I have precompiled framework with custom +load (some code are called before main() and I see logs from it), and I need to execute my code before this code (and as I understand - I can place it into +load, but I don't know how to change order). Or may be I can call my code before framework code with some other technique?
You really can't rely on order, nor can you effectively control order. By design. +load should happen before the +initialize of that class, but they order of the two is seemingly indeterminate across multiple classes (which I find slightly surprising, but well within the rules).
This is a big part of why you shouldn't do any heavy lifting in +load or +initialize. They really should only be used sparingly and only for initializing a small bit of highly localized state. Touching other significant subsystems is dangerous because you'll be changing initialization order and behavior in ways that might break the system. Shouldn't, but it might, it can, and it has in the past.
Instead, you really should try to have a "start here" point in your framework code that the client explicitly calls into.
+load methods are invoked by the objc runtime as part of the image loading process (you can see this by breaking in your load method and printing a stacktrace).
The order in which +load methods are invoked seems to depend on the order of the objc class lists generated by clang.
If you look at the source code of the objc runtime, you'll see that load_images (the function called by dyld), calls prepare_load_methods to get a list of all objc classes in an image. prepare_load_methods calls _getObjc2NonlazyClassList, which fetches the objc classlist from the __objc_nlclslist section in the image.
load_images then calls call_load_methods, which goes through all loaded classes and invokes their +load methods.
The project I am working on stores some constant strings like this:
(.h)
extern NSURL *kURLLocationComputer;
And I need to initialize them as follows:
(.mm)
NSURL *kURLLocationComputer;
... {
kURLLocationComputer = [[NSURL alloc] initWithString:#"computer:///"];
... }
The problem is that they are used from many various places in the project, and they need to be initialized first. But since some of the initializations are complex (not constant), they can't be done inline.
How should I ensure that they are initialized before being used? I was thinking of adding a dummy class and initializing the variables in +load, but I don't think one is allowed to assume that the Cocoa library classes are working by that point.
After some research, it turns out that __attribute__((constructor)) functions are guaranteed to be called after +load is called for all classes. From the NSObject documentation on +load:
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.
The order of initialization is as follows:
All initializers in any framework you link to.
All +load methods in your image.
All C++ static initializers and C/C++ __attribute__(constructor) functions in your image.
All initializers in frameworks that link to you.
Why do not you go for singleton class / Shared Instance.
That can be used as global variable throughout.
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.
How do I know which initializer is the designated initializer for ANY class?
I'm guessing that it is the one that takes the most parameters, but there could be times where this is not correct.
omz's answer can be stated more firmly: The documentation for a framework class will specify which is the designated initializer. It's necessary to know what the designated initializer is in order to write subclasses that behave properly. The subclass's D.I. must call up to the superclass's D.I. in order to be sure that it is properly initialized.
Your guess about the greatest number of parameters is well-founded, however. Apple actually states that it is often the D.I. in a few places.
Cocoa Core Competencies
The initializer of a class that takes the full complement of initialization parameters is usually the designated initializer.
Cocoa Fundamentals
Some subclasses provide convenience initializers that supply default values to an initializer that takes the full complement of initialization parameters. This initializer is usually the designated initializer, the most important initializer of a class.
You can't really know this without looking at either the source code (impossible for system frameworks) or the documentation (potentially of a superclass).
From BigNerdRanch iOS programming book:
*The designated initializer calls the superclass’s designated initializer (directly or indirectly) before doing anything else.
*Any other initializers call the class’s designated initializer (directly or indirectly).
*If a class declares a designated initializer that is different from its superclass, the superclass’s designated initializer must be overridden to call the new designated initializer (directly or indirectly).
Conway, Joe; Hillegass, Aaron; Keur, Christian (2014-02-14). iOS Programming: The Big Nerd Ranch Guide (4th Edition) (Big Nerd Ranch Guides) (Kindle Locations 1906-1910). Pearson Education. Kindle Edition.