I have a problem similar to this post, but that answer isn't working for me.
I have a singleton in my app which I used to create this way:
static POGalleryManager* defaultManager = nil;
+(POGalleryManager*)defaultManager
{
if (!defaultManager) {
defaultManager = [[super allocWithZone:NULL] init];
}
return defaultManager;
}
+(id)allocWithZone:(NSZone *)zone
{
return [self defaultManager];
}
This was working fine, so I tried to get clever and use GCD for thread safety, switching to this, which is supposed to be better:
+(POGalleryManager*)defaultManager
{
static POGalleryManager* __manager = nil;
dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__manager = [[POGalleryManager alloc] init];
});
return __manager;
}
The first time this gets called, everything is fine. The second time it gets called like this:
[[POGalleryManager defaultManager] someMethod];
someMethod never gets called. I tried stepping into that line with the debugger and once it got to the dispatch_once line it just continued execution (ie. it kicked me out of the debugger - so maybe the thread died?).
Any advice on this?
Try to switch the
dispatch_once_t onceToken;
for
static dispatch_once_t onceToken;
Related
There are different types of singleton implementation.
First:
static MyGlobalClass *instance = nil;
+(MyGlobalClass*)myinstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [MyGlobalClass new];
}
}
return instance;
}
Second:
+(PKShareClass *)sharedInstance
{
static PKShareClass *shaedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shaedInstance = [[PKShareClass alloc]init];
});
return shaedInstance;}
And finally with
static NSOperationQueue * _connectionQueue = nil;
+ (NSOperationQueue *) connectionQueue{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_connectionQueue)
{
_connectionQueue = [[NSOperationQueue alloc] init];
}
});
return _connectionQueue;
}
Here my question is what it means when we initialize like first and second ??
And third one with NSOperationQueue. What is the use when we initialize like third one?
Hard to find the meaning.
I'm afraid that i can't give you a link which can explain clearly about both 3 way but i will tell you what i understand.
First way: You create instance is a static variable of MyGlobalClass class. In myinstance method, you check if instance is initialized or not. If not, initialize instance. After all, return value of instance. Because instance is a static variable of MyGlobalClass so when you call [MyGlobalClass myinstance], it's always one object.
Second way: You create shaedInstance is a static variable of method sharedInstance. When you call dispatch_once(&onceToken, the code inside block is called only one time. About dispatch_once, you can take a look here. Because the initialization method is called only one time, shaedInstance is always one object when you return it. Actually, there is no different if shaedInstance is a static variable of PKShareClass class. You can use both 2 ways.
Third way: As you can understand after i explain about second way. This way is same like second way when shaedInstance is a static variable of PKShareClass class. But you don't need to check !_connectionQueue inside dispatch_once. Because it runs only one time and grossly it's always nil at the first time. This way can refactor like:
static NSOperationQueue * _connectionQueue = nil;
+ (NSOperationQueue *) connectionQueue{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (!_connectionQueue)
_connectionQueue = [[NSOperationQueue alloc] init];
});
return _connectionQueue;
}
Hope my answer can help you understand 3 ways easier ;)
+(Service *) sharedInstance
{
static LocationService *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ <<<< Crash
instance = [[self alloc]init];
});
return instance;
}
I am using the above shown code to create a singleton instance of service in my application. This is called from "AppDelegate application:willFinishLaunchingWithOptions:".
For most of the users, this code works fine. But for 2 users, the app crashes at "dispatch_once(&onceToken, ^{ " line.
They deleted the app and re-installed it. But they still see the issue. Only these 2 users are facing this issue. Others have never seen it. I have the .dsym, .crash and other relevant files to do further debugging. Just wanted to know how should I proceed with it? If someone has seen similar issue how did they proceed with fixing it?
Don't use self. Because self is not available before the initilization of class. Instead you can use class name as follows.
+(Service *) sharedInstance
{
static LocationService *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[Service alloc]init];
});
return instance;
}
I have a singleton that is initialized like all singletons, with something like this:
+ (MySingleton *)sharedInstance
{
static MySingleton *sharedMyInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyInstance = [[MySingleton alloc] init];
});
return sharedMyInstance;
}
In my case I want to add some code to initialize the singleton but because sharedInstance is a class method I cannot call instance methods from there.
So I always have to have this pattern:
MySingleton *sing = [MySingleton sharedInstance];
[sing initialize];
Ok, I can do this
MySingleton *sing = [[MySingleton sharedInstance] initialize];
but this will generate another problem because if initializing the singleton is the only thing I want at this point, sing is not being used and this is ugly code.
I suppose I can do simply
[[MySingleton sharedInstance] initialize];
and Xcode will not complain, but this does not sound good.
Is there another way to do this?
Check your code ;-) Specifically the line:
sharedMyInstance = [[MySingleton alloc] init];
You have to implement init and there is where you'll initialize the instance variables of your singleton (AKA shared instance). It will be called the first time the shared instance is used.
I have implemented a singleton object using the regular pattern. My question is: is it possible to set this object back to nil, so that on a later called to [MySingleton sharedInstance] the object gets re-initialised?
// Get the shared instance and create it if necessary.
+ (MySingleton *)sharedInstance {
static dispatch_once_t pred;
static MySingleton *shared = nil;
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
// We can still have a regular init method, that will get called the first time the Singleton is used.
- (id)init
{
self = [super init];
if (self) {
// Work your initialising magic here as you normally would
}
return self;
}
My guess is that
MySingleton *shared = [MySingleton sharedInstance];
shared = nil;
only sets the local pointer shared to nil. After all, shared is declared as static.
Your assumption about the local reference is correct, it won't affect your singleton.
To be able to reinitialize the singleton you need to move the static variable out of your method, so it's accessible by the whole class.
static MySingleton *sharedInstance = nil;
// Get the shared instance and create it if necessary.
+ (MySingleton *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
+ (void)resetSharedInstance {
sharedInstance = nil;
}
Note that you cannot use dispatch_once anymore, since your singleton needs obviously to be created multiple times. If you only ever call this singleton from your UI (and therefore only from the main thread), then the sample above is fine.
If you need access from multiple threads you need to put a lock around the +sharedInstance and +resetSharedInstance method, e.g.
+ (id)sharedInstance {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
}
+ (void)resetSharedInstance {
#synchronized(self) {
sharedInstance = nil;
}
}
This is quite a bit slower than the dispatch_once variant, but in practice it won't matter usually.
Yeah, but your singleton's sharedInstance method defines it as a static inside that method, and your final code sample is just setting a local variable (coincidentally also called shared) to nil, leaving the static inside sharedInstance unaltered. Thus you are just nil-ing a local pointer, not changing the static inside sharedInstance.
If you want to do what you're asking, you'll have to pull the static variable, shared, out of the sharedInstance method (and presumably write some reset method to nil it). Your sharedInstance method also can no longer rely upon dispatch_once, but rather have to check to see if that static is nil or not.
I did this. I'm not sure if it's the best way but it seemed to work fine.
static dispatch_once_t pred;
static MySingleton *shared = nil;
+(MySingleton *)sharedInstance {
dispatch_once(&pred, ^{
shared = [[MySingleton alloc] init];
});
return shared;
}
+(void)clearSharedInstance {
shared = nil;
pred = nil;
}
I'd like my class to detect that a new instance is equivalent (vis a vis isEqual: and hash) to some existing instance, and create only unique instances. Here's code that I think does the job, but I'm concerned it's doing something dumb that I can't spot...
Say it's an NSURLRequest subclass like this:
// MyClass.h
#interface MyClass : NSMutableURLRequest
#end
// MyClass.m
#implementation MyClass
+ (NSMutableSet *)instances {
static NSMutableSet *_instances;
static dispatch_once_t once;
dispatch_once(&once, ^{ _instances = [[NSMutableSet alloc] init];});
return _instances;
}
- (id)initWithURL:(NSURL *)URL {
self = [super initWithURL:URL];
if (self) {
if ([self.class.instances containsObject:self])
self = [self.class.instances member:self];
else
[self.class.instances addObject:self];
}
return self;
}
// Caller.m
NSURL *urlA = [NSURL urlWithString:#"http://www.yahoo.com"];
MyClass *instance0 = [[MyClass alloc] initWithURL: urlA];
MyClass *instance1 = [[MyClass alloc] initWithURL: urlA]; // 2
BOOL works = instance0 == instance1; // works => YES, but at what hidden cost?
Questions:
That second assignment to self in init looks weird, but not insane.
Or is it?
Is it just wishful coding to think that second alloc (of instance1) gets magically cleaned up?
It's not insane, but in manual retain/release mode, you do need to release self beforehand or you'll leak an uninitialized object every time this method is run. In ARC, the original instance will automatically be released for you.
See #1.
BTW, for any readers who usually stop at one answer, bbum's answer below includes a full working example of a thread-safe implementation. Highly recommended for anyone making a class that does this.
Thought of a better way (original answer below the line) assuming you really want to unique by URL. If not, this also demonstrates the synchronization primitive use.
#interface UniqueByURLInstances:NSObject
#property(strong) NSURL *url;
#end
#implementation UniqueByURLInstances
static NSMutableDictionary *InstanceCache()
{
static NSMutableDictionary *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [NSMutableDictionary new];
});
return cache;
}
static dispatch_queue_t InstanceSerializationQueue()
{
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("UniqueByURLInstances queue", DISPATCH_QUEUE_SERIAL);
});
return queue;
}
+ (instancetype)instanceWithURL:(NSURL*)URL
{
__block UniqueByURLInstances *returnValue = nil;
dispatch_sync(InstanceSerializationQueue(), ^{
returnValue = [InstanceCache() objectForKey:URL];
if (!returnValue)
{
returnValue = [[self alloc] initWithURL:URL];
}
});
return returnValue;
}
- (id)initWithURL:(NSURL *)URL
{
__block UniqueByURLInstances* returnValue = self;
dispatch_sync(InstanceSerializationQueue(), ^{
returnValue = [InstanceCache() objectForKey:URL];
if (returnValue) return;
returnValue = [super initWithURL:URL];
if (returnValue) {
[InstanceCache() setObject:returnValue forKey:URL];
}
_url = URL;
});
return returnValue;
}
- (void)dealloc {
dispatch_sync(InstanceSerializationQueue(), ^{
[InstanceCache() removeObjectForKey:_url];
});
// rest o' dealloc dance here
}
#end
Caveat: Above was typed into SO -- never been run. I may have screwed something up. It assumes ARC is enabled. Yes, it'll end up looking up URL twice when using the factory method, but that extra lookup should be lost in the noise of allocation and initialization. Doing that means that the developer could use either the factory or the initializer and still see unique'd instances but there will be no allocation on execution of the factory method when the instance for that URL already exists.
(If you can't unique by URL, then go back to your NSMutableSet and skip the factory method entirely.)
What Chuck said, but some additional notes:
Restructure your code like this:
+(NSMutableSet*)instances
{
static NSMutableSet *_instances;
dispatch_once( ...., ^{ _instances = [[NSMutableSet alloc] init];});
return instances;
}
Then call that method whenever you want access to instances. It localizes all the code in one spot and isolates it from +initialize (which isn't really a big deal).
If your class may be instantiated from multiple threads, you'll want to surround the check-allocate-or-return with a synchronization primitive. I would suggest a dispatch_queue.