Objective-C +load function with dispatch_once - objective-c

+ (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

Related

Objective-C: How to force a call to `+initialize` at startup rather than later when the class happens to used for the first time?

Problem
For certain classes, I would like to explicitly call the +initialize method when my program starts, rather than allowing the runtime system to call it implicitly at some nondeterministic point later when the class happens to first be used. Problem is, this isn't recommended.
Most of my classes have little to no work to do in initialization, so I can just let the runtime system do its thing for those, but at least one of my classes requires as much as 1 second to initialize on older devices, and I don't want things to stutter later when the program is up and running. (A good example of this would be sound effects — I don't want sudden delay the first time I try to play a sound.)
What are some ways to do this initialization at startup-time?
Attempted solutions
What I've done in the past is call the +initialize method manually from main.c, and made sure that every +initialize method has a bool initialized variable wrapped in a #synchronized block to prevent accidental double-initialization. But now Xcode is warning me that +initialize would be called twice. No surprise there, but I don't like ignoring warnings, so I'd rather fix the problem.
My next attempt (earlier today) was to define a +preinitialize function that I call directly instead +initialize, and to make sure I call +preinitialize implicitly inside of +initialize in case it is not called explicitly at startup. But the problem here is that something inside +preinitialize is causing +initialize to be called implicitly by the runtime system, which leads me to think that this is a very unwise approach.
So let's say I wanted to keep the actual initialization code inside +initialize (where it's really intended to be) and just write a tiny dummy method called +preinitialize that forces +initialize to be called implicitly by the runtime system somehow? Is there a standard approach to this? In a unit test, I wrote...
+ (void) preinitialize
{
id dummy = [self alloc];
NSLog(#"Preinitialized: %i", !!dummy);
}
...but in the debugger, I did not observe +initialize being called prior to +alloc, indicating that +initialize was not called implicitly by the runtime system inside of +preinitialize.
Edit
I found a really simple solution, and posted it as an answer.
The first possible place to run class-specific code is +load, which happens when the class is added to the ObjC runtime. It's still not completely deterministic which classes' +load implementations will be called in what order, but there are some rules. From the docs:
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.
So, two peer classes (say, both direct NSObject subclasses) will both +load in step 2 above, but there's no guarantee which order the two of them will be relative to each other.
Because of that, and because metaclass objects in ObjC are generally not great places to set and maintain state, you might want something else...
A better solution?
For example, your "global" state can be kept in the (single) instance of a singleton class. Clients can call [MySingletonClass sharedSingleton] to get that instance and not care about whether it's getting its initial setup done at that time or earlier. And if a client needs to make sure it happens earlier (and in a deterministic order relative to other things), they can call that method at a time of their choosing — such as in main before kicking off the NSApplication/UIApplication run loop.
Alternatives
If you don't want this costly initialization work to happen at app startup, and you don't want it to happen when the class is being put to use, you have a few other options, too.
Keep the code in +initialize, and contrive to make sure the class gets messaged before its first "real" use. Perhaps you can kick off a background thread to create and initialize a dummy instance of that class from application:didFinishLaunching:, for example.
Put that code someplace else — in the class object or in a singleton, but in a method of your own creation regardless — and call it directly at a time late enough for setup to avoid slowing down app launch but soon enough for it to be done before your class' "real" work is needed.
There are two problems here. First, you should never call +initialize directly. Second, if you have some piece of initialization that can take over a second, you generally shouldn't run it on the main queue because that would hang the whole program.
Put your initialization logic into a separate method so you can call it when you expect to. Optionally, put the logic into a dispatch_once block so that it's safe to call it multiple times. Consider the following example.
#interface Foo: NSObject
+ (void)setup;
#end
#implementation Foo
+ (void)setup {
NSLog(#"Setup start");
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(#"Setup running");
[NSThread sleepForTimeInterval:1]; // Expensive op
});
}
#end
Now in your application:didFinishLaunchingWithOptions: call it in the background.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(#"START");
// Here, you should setup your UI into an "inactive" state, since we can't do things until
// we're done initializing.
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
[Foo setup];
// And any other things that need to intialize in order.
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(#"We're all ready to go now! Turn on the the UI. Set the variables. Do the thing.");
});
return YES;
}
This is how you want to approach things if order matters to you. All the runtime options (+initialize and +load) make no promises on order, so don't rely on them for work that needs that. You'll just make everything much more complicated than it needs to be.
You may want to be able to check for programming errors in which you accidentally call Foo methods before initialization is done. That's best done, IMO, with assertions. For example, create an +isInitialized method that checks whatever +setup does (or create a class variable to track it). Then you can do this:
#if !defined(NS_BLOCK_ASSERTIONS)
#define FooAssertInitialized(condition) NSAssert([Foo isInitialized], #"You must call +setup before using Foo.")
#else
#define FooAssertInitialized(condition)
#endif
- (void)someMethodThatRequiresInitialization {
FooAssertInitialized();
// Do stuff
}
This makes it easy to mark methods that really do require initialization before use vs ones that may not.
Cocoa provides a setup point earlier than +initialize in the form of +load, which is called very shortly after the program's start. This is a weird environment: other classes that rely on +load may not be completely initialized yet, and more importantly, your main() has not been called! That means there's no autorelease pool in place.
After load but before initialize, functions marked with __attribute__((constructor)) will be called. This doesn't allow you to do much that you can't do in main() so far as I know.
One option would be to create a dummy instance of your class in either main() or a constructor, guaranteeing that initialize will be called as early as possible.
Answering my own question here. It turns out that the solution is embarrassingly simple.
I had been operating under the mistaken belief that +initialize would not be called until the first instance method in a class is invoked. This is not so. It is called before the first instance method or class method is invoked (other than +load, of course).
So the solution is simply to cause +initialize to be invoked implicitly. There are multiple ways to do this. Two are discussed below.
Option 1 (simple and direct, but unclear)
In startup code, simply call some method (e.g., +class) of the class you want to initialize at startup, and discard the return value:
(void)[MyClass class];
This is guaranteed by the Objective-C runtime system to call [MyClass initialize] implicitly if it has not yet been called.
Option 2 (less direct, but clearer)
Create a +preinitialize method with an empty body:
+ (void) preinitialize
{
// Simply by calling this function at startup, an implicit call to
// +initialize is generated.
}
Calling this function at startup implicitly invokes +initialize:
[MyClass preinitialize]; // Implicitly invokes +initialize.
This +preinitialize method serves no purpose other than to document the intention. Thus, it plays well with +initialize and +deinitialize and is fairly self-evident in the calling code. I write a +deinitialize method for every class I write that has an +initialize method. +deinitialize is called from the shutdown code; +initialize is called implicitly via +preinitialize in the startup code. Super simple. Sometimes I also write a +reinitialize method, but the need for this is rare.
I am now using this approach for all my class initializers. Instead of calling [MyClass initialize] in the start up code, I am now calling [MyClass preinitialize]. It's working great, and the call stack shown in the debugger confirms that +initialize is being called exactly at the intended time and fully deterministically.

In Objective-C, what gets called before main?

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

Objective C and magic methods in class

Does objective-c offer a way to intercept calls to class method that does not exist?
The forwardInvocation method is what you are going to want to use. It is called automatically when a non-existent selector is called on an object. The default behavior of this method is to call doesNotRecognizeSelector:(which is what outputs debug information to your console), but you can override it do anything you want. One recommended approach by Apple is to have this method forward the method invocation to another object.
- (void)forwardInvocation:(NSInvocation *)anInvocation
Note that forwardInvocation is a fairly expensive operation. An NSInvocation object needs to be created by the framework and (optionally) used to invoke a selector on another instance. If you are looking for a (relatively) faster method of detecting non-existent selectors then you can choose to implement forwardingTargetForSelector instead.
- (id)forwardingTargetForSelector:(SEL)aSelector
You should Apple's documentation for how to override these methods effectively, there are some gotcha's to watch out for, particularly when overriding the forwardInvocation method on the same object that will have the missing selectors.
Yes, you can with the resolveClassMethod: class method (which is defined on NSObject):
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html
Here is also something to watch out for (stumped me the first time): http://iphonedevelopment.blogspot.com/2008/08/dynamically-adding-class-objects.html

Method Swizzling - How to assure methods are swizzled before they are called

I'm method swizzling a third party applications creation of NSMenuItems with SIMBL, but 50/50 of the time the menu-items are created before my method swizzling is initialized.
What is a clean way to make sure my swizzling always comes first? I guess I could swizzle applicationDidFinishLaunching: and continue my swizzling there. But I'm afraid I'm going to run in to the same error there, where applicationDidFinishLaunching will be called before my actual swizzle is in place.
John
You'd want the swizzle to happen as soon as the libraries are loaded. You can do that via +initialize, +load, or a constructor function.
#bbum's answer to this question has a bit more information, along with one of his blog posts on the caveats of using these special class methods.
(And I'm purposely not questioning the wisdom of what you're doing ;) )
You can use constructor functions like this:
__attribute__((constructor)) static void do_the_swizzles()
{
// Do all your swizzling here.
}
From GCC documentation:
The constructor attribute causes the function to be called
automatically before execution enters main().
Note: Although this is originally from GCC, it also works in LLVM.

#synchronized in a static method

In Objective-C, you can declare a block as being synchronized on some object by using the #synchronized construct. It would look something like this:
#synchronized (self) {
// Do something useful
}
However, I'm curious what exactly self is referring to when you have a static method (+ instead of -). I tried looking through the Apple docs, and they allude to it being OK, but don't really explain it. I know it works, I'm just curious what it means.
self inside of a class (static) method refers to the class object.
In Objective-C self is determined by context. In an instance method, that would be the instance being called. In a static method, it would be the class object itself (i.e. the result of [self class] in an instance method)
With the answers above, just keep in mind that if one thread calls an instance method using #synchronized (self), and another thread calls a class method using #synchronized (self), no synchronisation will happen between the two calls, because they are using different objects for synchronisation.