What are the implications of creating a singleton class with:
+ (id)sharedCoordinator {
static MyCoordinator *sharedCoordinator = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedCoordinator = [[self alloc] init];
});
}
or as an instance method in the Application Delegate with class method:
- (CoreDataHelper *)cdh {
if (!_coreDataHelper) {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
_coreDataHelper = [CoreDataHelper new];
});
[_coreDataHelper setupCoreData];
}
return _coreDataHelper;
}
I have seen them both used, and would like to learn how they affect performance, simple code, debugging, etc.
The main difference is that the second code snippet has an error: when cdh is accessed concurrently from multiple threads, there is a possibility of [_coreDataHelper setupCoreData] being called twice.
This would happen if multiple threads arrived at cdh at the time when _coreDataHelper is nil. Only one of these threads would proceed to make the [CoreDataHelper new] call, yet all threads would end up in the setupCoreData method.
The proper way of doing initialization is to place the setup call into the block, and make the call unconditional:
- (CoreDataHelper *)cdh {
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
_coreDataHelper = [CoreDataHelper new];
[_coreDataHelper setupCoreData];
});
return _coreDataHelper;
}
Now the two snippets look almost identical. The only difference is that the first snippet uses a method-static variable to store the singleton, while the updated second snippet "piggybacks" on the instance of app delegate.
This does not create any performance differences worth discussing. The biggest difference is that the first snippet lets you access the singleton without creating an additional dependency on the app delegate, which is a good thing: this avoids "polluting" your app delegate with code that is not directly relevant to the application state.
The first allows the Singleton class to be re-used in other places.
The second makes the single instance private to the app delegate.
Generally the first option is better (IMHO.) It allows you to reuse the single instance in a structured way anywhere in your code.
The second option can provide a guarantee of being a single instance, privately accessible in one place. That is probably useful in some circumstances, but it isn't really a Singleton. You could make this a public property on the AppDelegate, but then why not use a Singleton class?
As for performance considerations, they should be negliable. The only one I can think of is the slight extra overhead in the runtime caused by having an extra class object in your code.
Related
I've been reading around and its hard to get a clear feel if I have written a thread safe implementation here.
My getter looks like
+ (MySingleton *)getSingleton
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[MySingleton alloc] init];
});
return singleton;
}
And my setter is:
+ (void)updateSingleton:(MySingleton *)newSingleton
{
#syncronized(self) {
singleton = newSingleton;
}
}
No, that isn't thread safe. Your exclusion mechanism between your two modification methods are not the same. dispatch_once has nothing to do with #synchronized in any way.
Beyond that a singleton must never be replaced by definition. A singleton can come into existence at any time and, once it does, it never, ever, goes away.
Also, getSingleton should be sharedInstance or some similar objective-c standard moniker. Methods should never be prepended with get unless they are returning stuff by reference.
What is the difference between dispatch_once and using runtime conditional check for the property that requires only once initialization
Method 1: runtime checking
- (MyProp *)myProp{
if (!_myProp){
_myProp = [[MyProp alloc] init];
}
return _myProp;
}
Method 2: use dispatch_once
- (MyProp *)myProp{
dispatch_once_t once;
dispatch_once(&once, ^{
_myProp = [[MyProp alloc] init];
}
return _myProp;
}
I guess that method 2 is somehow faster but not really sure.
Could anyone give me any deal?
Thanks
dispatch_once is thread safe. So if two threads call myProp for the first time simultaneously, dispatch_once ensures only one initializes the variable. Method 1 may initialize the variable twice, and could even corrupt memory such that the reference is invalid. Once the property has been initialized, these behave identically.
Method 2 is actually slightly slower than Method 1, particularly during the first initialization. But in the usual case (reading after initialization), it is extremely close (possibly identical) in performance. If you want a much more in-depth exploration of how it works and why, see Mike Ash's Secrets of dispatch_once.
Note that your Method 2 code is incorrect. You've made once an automatic local variable. It needs to be static or dispatch_once can't do its job. What you meant was:
- (MyProp *)myProp{
static dispatch_once_t once; // <--- this "static" is critical
dispatch_once(&once, ^{
_myProp = [[MyProp alloc] init];
}
return _myProp;
}
Does locking in one function from a thread, blocks all other thread trying to acquire the lock in different functions.
We can use gcd for accessing the critical sections mentioned below, just wanted to know how #synchronized(self) works.
For ex.
Do multiple threads with ONLY writeString() calls gets blocked when the execution is in #synchronized(self){ } in writeString()?
OR
all the threads calling the functions of the same class with #synchronized(self){} (e.g.readDataFromFile()) gets blocked when execution is in #synchronized(self){ } in writeString() ?
-(void)writeString:(NSString*)string forObj:(id)obj
{
#synchronized(self)
{
[obj write:string];
}
}
-(void)readDataFromFile:(NSString*)file
{
#synchronized(self)
{
[self read];
}
}
#synchronized(A) can be thought of as a lock where A identifies the lock to use.
If you pass the same value for A into two calls to #synchronized(), then they'll use the same lock and be exclusive. If you pass two different values for two calls, then they will not be exclusive.
So for this one, we need to zoom out to a bit of a larger context.
In the case where you have two instances:
YourClass *a = [[YourClass alloc] init];
YourClass *b = [[YourClass alloc] init];
a will sync access to both methods for itself.
b will sync access to both methods for itself.
So for instance, concurrently from two different threads, a and b can both run -writeString:forObj: at the same time without blocking.
Now if you changed the implementation to use #synchronized(self.class) that entirely changes the game. Rather than syncing on the 'instance', you would be syncing on the 'class' as a whole, so every instance would have to sync access to the methods.
So for instance using the use #synchronized(self.class) implementation, concurrently from two different threads, if a and b both run -writeString:forObj: at the same time, that would then serialize those calls so only one runs while the other is blocked waiting for the sync to unlock.
I hope that clarifies the difference between locking on an instance of a class vs locking every instance for a given class.
Edit:
May also be worth noting, if you use #synchronized(self) in a 'class' method like the following:
// implementation of 'ExampleClass'
+(void)serializeWriting:(NSString*)string toObj:(id)obj {
#synchronized(self) {
[obj write:string];
}
}
That also changes the game, so anytime that method is called, its synced against the class itself, so something like [ExampleClass serializeWriting:#"some string" toObj:somethingElse] would only ever run the critical section [obj write:string] on a single thread no matter how many places/threads it was called from.
I'm implementing a singleton class (and lets not get into the discussion if that is wrong or not). I have a method to get the instance of this class, which is lazily initialized:
+ (FFDataManager *)sharedDataManager {
static FFDataManager *dm = nil;
if (!dm) {
dm = [[FFDataManager alloc] init];
}
return dm;
}
Is there anything I should look out for when doing this using static (inside of the method) as opposed to creating a global variable? Is there anything that can go wrong, all tutorials on the Internet use a global variable.
My preferred singleton implementation looks like:
+ (MyClass *) sharedInstance {
static dispatch_once_t predicate = 0;
__strong static MyClass *shared = nil;
dispatch_once(&predicate, ^{
shared = [[self alloc] init];
});
return shared;
}
Using dispatch_once makes sure this is also thread safe. Your code would allocate twice when accessed by multiple threads at the same time.
To answer the original question (others have address the best way to do initialization):
Is there anything I should look out for when doing this using static (inside of the method) as opposed to creating a global variable?
No.
The difference is over visibility and not lifetime.
A global's (with or without static) lifetime is that of the application execution.
A global without static is visible throughout the whole application. From anywhere else it can be referenced by naming it in an extern statement.
A global with static is visible just in the containing compilation unit (which is typically a single file, but #import/#include can change that).
A variable declared within a function/method as static is a global which is only visible within that function/method.
If you're using a global in just one function what you've done is good - it limits the visibility to just where it is needed while keeping execution-lifetime. Any initializer is run once, just as for file-level globals.
What you create is a static local variable. Static local variables retain their value through successive method invocations. They can only be accessed from within the method which they are defined in. When apps start static local variables are set to 0 once.
So what you do in my opinion is with every call of sharedDataManager you declare a new static local variable and set it to nil. I don't think that's necessary or even good. And also every time if (!dm) checks dm it is nil because you set dm to nil the line before.
I'd go with the static global approach.
Edit:
Have a look at http://www.johnwordsworth.com/2010/04/iphone-code-snippet-the-singleton-pattern/
I have two static methods/selectors in the same class, one passes the other as a callback to an external method. However, how I have it coded I get an error. This worked when both the methods were instance methods, and I've read it can work when the first method is an instance method using [self class]. However, I haven't found information when both are static, and I haven't got it to work.
+(void)Validate {
Callback *managerCallback = [[[Callback alloc] initWithTarget:self Action:#selector(Parse:)] autorelease];
...
}
+(void)Parse:(Callback *)managerCallback {
...
}
Thanks!
Callback *managerCallback = [[[Callback alloc] initWithTarget:self Action:#selector(Parse:)] autorelease];
That line of code is setup to call the instance method Parse:, not a class method as you have it defined.
Objective-C does not have static methods. It has class methods and instance methods.
As well, your methods should start with lowercase letters.
Herp-da-derp. Dave is right.
Given this:
+(void)Validate {
Callback *managerCallback = [[[Callback alloc] initWithTarget:self Action:#selector(Parse:)] autorelease];
...
}
+(void)Parse:(Callback *)managerCallback {
...
}
Some comments:
methods should start with lowercase letters
it is exceedingly odd to use a class in such a role; even if you really only ever need one of 'em, use an instance. At the least, the instance is a convenient bucket to toss state in and it'll make refactoring in the future much easier if you ever need two.
The above pattern makes the assumption (and I ASSumed) that the instance of Callback is retained. For callbacks, timers, and some other patterns, this is typical; retain the target until the target is called for the last time. Then release (or autorelease). However, notification centers do not do this. Nor are delegates retained, typically.
Turns out the code is written correctly to do what I wanted to, but because callback was set to autorelease, the object was getting released before the callback was being processed.