aryaxt
aryaxt

Reputation: 77626

Objective C - Category to modify a singleton object?

I know that the whole point of singleton is to instantiate 1 instance of the onject and reuse it, but when it comes to unit testing I want to be able to renew the singleton object before every test.

I tried to use a category to access the singleton object and release it but It's not accessible by categories any idea what's the best way to achieve this?

@implementation SingletonClass

static SingletonClass *singleton;

+ (SingletonClass*)sharedInstance
{
   if (!singleton)
   {
      singleton = [[SingletonClass alloc] init];
   }
   return singleton;
}

@end

.

@implementation SingletonClass(Unit Testing Additions)

+ (void)killInstance
{
   // I get an error here and I cannot access the singleton Object
   [singleton release], singleton = nil;
}

@end

Upvotes: 0

Views: 1426

Answers (4)

aryaxt
aryaxt

Reputation: 77626

Here is my own solution.

@implementation SingletonClass(Unit Testing Additions)

//Override
static SingletonClass *singleton;

+ (void)killInstance
{
   // I get an error here and I cannot access the singleton Object
   [singleton release], singleton = nil;
}

//Override
+ (SingletonClass*)sharedInstance
{
   if (!singleton)
   {
      singleton = [[SingletonClass alloc] init];
   }
   return singleton;
}

@end

Upvotes: 0

bbum
bbum

Reputation: 162722

By the very definition of singleton, you can't do this.

If it is your class, don't make it a singleton.

If it isn't your class, doing this will fail.

Upvotes: 3

Nick Forge
Nick Forge

Reputation: 21464

If you want access to your singleton global variable outside of the file in which it's declared, you'll need to make it globally accessible using extern.

At the top of SingletonClass.h, put this:

extern SingletonClass *singletonClassSingleton;

In your SingletonClass.m, use this:

SingletonClass *singletonClassSingleton = nil;

Then assuming you have #import "SingletonClass.h" in your unit test .m file, you should be able to add:

@implementation SingletonClass(Unit Testing Additions)

+ (void)killInstance
{
   [singletonClassSingleton release], singletonClassSingleton = nil;
}

@end

The reason I've renamed singleton to singletonClassSingleton is that the variable is now global - if you have a bunch of singleton classes, you need these variables to have unique names, like dataManagerSingleton, resourceManagerSingleton or whatever.

Upvotes: 0

dreamlax
dreamlax

Reputation: 95355

I'm not sure whether this will work, but maybe you could just override the sharedInstance class method and manage the singleton yourself:

@implementation SingletonClass (Unit Testing Additions)

static SingletonClass *myVeryOwnSharedInstance;

+ (SingletonClass *) sharedInstance
{
    if (!myVeryOwnSharedInstance)
        myVeryOwnSharedInstance = [[self alloc] init];
    return myVeryOwnSharedInstance;
}

+ (void) killInstance
{
    [myVeryOwnSharedInstance release];
    // if release is overridden to do no-op, maybe just invoke -dealloc directly
    myVeryOwnSharedInstance = nil;
}

@end

Upvotes: 1

Related Questions