#synchronized in a static method - objective-c

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.

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.

iOS - Cannot use 'super' as a reference?

I'm trying to use an NSInvocation to invoke a superclass method from the subclass. The code involved is relatively straightforward, it goes like:
- (NSInvocation*) invocationWithSelector:(SEL)selector {
NSInvocation* call = [[NSInvocation alloc] init];
[call retainArguments];
call.target = super; //ERROR: use of undeclared identifier 'super'
call.selector = #selector(selector);
return call;
}
This seems a bit odd to me, as I had always assumed that super followed pretty much the same rules as self (i.e. it could be treated as a direct reference to the object in question and assigned to variables, used as a return value, etc.). It appears that this is not the case in practice.
Anyhow, is there any simple way to get my NSInvocation to target the superclass implementation (I cannot use self as the target, because the subclass overrides the superclass methods), or do I need to look for some other approach?
See What exactly is super in Objective-C? for more info, but super is not actually an object. Super is a keyword for the compiler to generate obj-c runtime calls (specifically objc_msgSendSuper). Basically, it is like casting your class to its superclass before sending it the message.
EDIT So if you've overriden the method you want to call, you are going to have to write another method to call [super method] directly and set your invocation to call that method instead. The runtime will only send messages to objects, and they will be dealt with at the lowest member of the inheritance chain that implements them.
super and self are the same object, so just use
call.target = self;
The difference between them is that you can use super as a receiver of a message to self as a way to ensure that it invokes the superclass' implementation.

Using #synchronized(self) { ... } in class-function

Accidentally I have been using a #synchronized block with the semaphore self in a class method.
+(void)someFunction {
#synchronized(self) {
/* some code */
}
}
It seems to be valid code, at least the compiler does not give me any bad feedback. My question is: what is self here? As far as I can tell the #synchronized block didn't work, but it didn't crash either.
I'm just asking out of curiousity.
self in this instance refers to the class, instead of an instance. In ObjC, classes are themselves objects.
self in this context is the class itself, it's perfectly fine to use #synchronized in a class function since they are also Objective-C objects.
The #synchronized syntax is a compiler extension for mutex implementation. I assume you understood what it does. The compiler will translate it into something else, supposedly something similar to critical section because it's less CPU intensive. Locks need to be tracked. The implementation will use an object to record the state of the lock, to keep its integrity (i.e. a lock shouldn't be acquired twice, or unlocked twice).
In #synchronized(self), the object doesn't have to be self. It could be any objective-c object. Note that a single #synchronized block usually does nothing (when you mentioned it's not working, it's actually behaving correctly). But when you have two #synchronized blocks on the same object, only one block will be executed at the same time, the other block would have to wait for the lock to be unlocked (i.e. the first block finishes). This helps to keep things synchronized as in a multithreaded environment.
In a class method self is the class that the method is being called on. For example you can call other class methods of the same class using self. [MyClass someFunction] and [self someFunction] would be the equivalent to recursively calling someFunction. The #synchronized block I am sure worked as it was supposed to.

Accessing Singleton Instance Variable in Class Methods Throws Warning?

I've using the Objective-C singleton from here at stackoverflow.
The singleton in the class method accesses it's instance variable, which works, but throws a complie warning. How should I be doing this? Is there a way to do this without accessing the sharedInstance: in each class method?
for example here is my class method:
+ (NSString *)myClassMethods {
[instanceDateFormatter setFormat:#"MM"];
return [instanceDateFormatter stringWithDate:somedate];
}
line 2 will have the complie warning.
Thanks,
Ross
You should be using the sharedInstance: call in each class method. I guess if you really want to, you could work around it with global variables, but the right solution is as you mentioned.
Since instanceDataFormatter is an instance variable, you have to access it via a class instance -- so you'll need to go through your sharedInstance method to get it. Or, you could access it via the static singleton variable, bypassing the call to sharedInstance (however, that could break if the static variable hasn't been initialized yet).

Is `super` local variable?

// A : Parent
#implementation A
-(id) init
{
// change self here then return it
}
#end A
A *a = [[A alloc] init];
a. Just wondering, if self is a local variable or global? If it's local then what is the point of self = [super init] in init? I can successfully define some local variable and use like this, why would I need to assign it to self.
-(id) init
{
id tmp = [super init];
if(tmp != nil) {
//do stuff
}
return tmp;
}
b. If [super init] returns some other object instance and I have to overwrite self then I will not be able to access A's methods any more, since it will be completely new object? Am I right?
c. super and self pointing to the same memory and the major difference between them is method lookup order. Am I right?
sorry, don't have Mac to try, learning theory as for now...
Dreamlax's answer is correct... but, clarification may be helpful.
a. Just wondering, if self is a local
variable or global? If it's local then
what is the point of self = [super
init] in init? I can successfully
define some local variable and use
like this, why would I need to assign
it to self.
self is not a local variable. It is an argument to the method call. The first argument, in fact. The second argument is _cmd, the name of the selector of the method being executed.
What is special about self is that self is used by the compiler to access instance variables. That is, if you say self = [super init] and the superclass's init happens to return something different, any further instance variable accesses will still be correct.
b. If [super init] returns some other
object instance and I have to
overwrite self then I will not be able
to access A's methods any more, since
it will be completely new object? Am I
right?
If super's init returns an instance of something that is incompatible with A, then something has gone horribly awry in the design of the superclass. Keep in mind that Objective-C is fully dynamic. Thus, there is no reason that whatever is returned by super's init actually needs to be an instance of A, but it better had damned well act like an A. Now, it could be a completely new instance of a subclass of A and, thus, all of the methods of A will work just fine.
Reading between the lines; remember that Objective-C is fully dynamic. There is no such thing as static method dispatch. The class of an object could change at any time and any random method call will still work as long as the new class responds to the method. Not that this actually happens at runtime, just that it could.
c. super and self pointing to the same
memory and the major difference
between them is method lookup order.
Am I right?
Now, this is the fun question. super doesn't really point to anything. For all intents and purposes, super can be treated as the one bit of magic in this. That is, when the compiler sees super as the target of a method call, it compiles it as a slightly different call site that calls through to one of the variants of objc_msgSendSuper() which -- as name implies -- effectively "searches" for the method's implementation starting in the parent class of the class within which the call was compiled.
Self is an argument provided to the method implementation. All Objective-C instance and class methods have two implicit arguments that precede the method's arguments. The implicit arguments are self and _cmd. _cmd is the selector used to determine the method implementation.
If super returns an instance of a different class, then that would be the case, but it is also possible that it may return a different instance of the same class.
super is a keyword, not a variable. It informs the compiler to use a different runtime function that begins method resolution at one class higher than the current class.