Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to set singleton back to nil?

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.

like image 607
Chuckels5584 Avatar asked Jun 28 '13 16:06

Chuckels5584


3 Answers

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.

like image 95
Alfonso Avatar answered Nov 06 '22 17:11

Alfonso


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.

like image 20
Rob Avatar answered Nov 06 '22 17:11

Rob


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;
}
like image 32
Hackmodford Avatar answered Nov 06 '22 16:11

Hackmodford