Elegant and 'correct' multiton implementation in Objective C? - objective-c

Would you call this implementation of a multiton in objective-c 'elegant'? I have programmatically 'disallowed' use of alloc and allocWithZone: because the decision to allocate or not allocate memory needs to be done based on a key.
I know for sure that I need to work with only two instances, so I'm using 'switch-case' instead of a map.
#import "Multiton.h"
static Multiton *firstInstance = nil;
static Multiton *secondInstance = nil;
#implementation Multiton
+ (Multiton *) sharedInstanceForDirection:(enum KeyName)direction {
return [[self allocWithKey:direction] init];
}
+ (id) allocWithKey:(enum KeyName)key {
return [self allocWithZone:nil andKey:key];
}
+ (id) allocWithZone:(NSZone *)zone andKey:(enum KeyName)key {
Multiton **sharedInstance;
#synchronized(self) {
switch (key) {
case KEY_1:
sharedInstance = &firstInstance;
break;
case KEY_2:
sharedInstance = &secondInstance;
break;
default:
[NSException raise:NSInvalidArgumentException format:#"Invalid key"];
break;
}
if (*sharedInstance == nil)
*sharedInstance = [super allocWithZone:zone];
}
return *sharedInstance;
}
+ (id) allocWithZone:(NSZone *)zone {
//Do not allow use of alloc and allocWithZone
[NSException raise:NSObjectInaccessibleException format:#"Use allocWithZone:andKey: or allocWithKey:"];
return nil;
}
- (id) copyWithZone:(NSZone *)zone {
return self;
}
- (id) retain {
return self;
}
- (unsigned) retainCount {
return NSUIntegerMax;
}
- (void) release {
return;
}
- (id) autorelease {
return self;
}
- (id) init {
[super init];
return self;
}
#end
PS: I've not tried out if this works as yet, but its compiling cleanly :)

I find singletons a bad idea and this looks about four times as horrible. The code is quite complex, you can be sure of spending a nice few hours chasing subtle bugs in it and you will probably never feel comfortable about it. That’s no good. You should throw this abomination away and wire your objects together in some other way that doesn’t require so much thinking.
If you like patterns, you can use something akin to Factory pattern to wire your objects. The Factory will take care of creating those two instances and passing them wherever needed. And the Factory will be a lot more simple than Multiton:
#interface Factory : NSObject {
Foo *foo1, *foo2;
}
#end
#implementation Factory
- (id) init {
[super init];
foo1 = [[Foo alloc] init];
foo2 = [[Foo alloc] init];
return self;
}
Of course you don’t have to create both instances at once. You can do anything you like there – cache, lazy load, anything. The point is leaving the Foo lifetime management up to the Factory, separate from the Foo code. Then it gets much easier. ¶ All the other objects that need Foo will be created and wired through Factory and will receive their Foo through a setter:
#implementation Factory
- (id) wireSomeClass {
id instance = [[SomeClass alloc] init];
[instance setFoo:foo1];
[instance setAnotherDependency:bar];
return [instance autorelease];
}
This is all much more straightforward then the code from your question.

Don't override alloc. The problem with overriding alloc to return a previously allocated instance of the class, as you do, is that when +sharedInstance calls [[Multiton alloc] init]... +alloc will return the old instance, then -init will re-initialize it! The best practice is to override -init, doing the cache lookup and calling [self release] before you return the cached instance.
If you're really concerned about the cost of that extra +alloc (it's not much), you also do your cache lookup in +sharedInstance and then ensure that all of your clients access the instance through +sharedInstance to avoid the extra alloc.

Point of order: How do you know that you'll only ever have two instances, or need to have two instances? (Or want to have two instances?) What, exactly, is the point of having a "Multiton"? (And is that even a word?)

Related

Objective-C, class identity

I have the following situation, i can't resolve:
#interface Deck : NSObject
#interface MasterDeck : Deck
#interface PlayerDeck : Deck
Inside MasterDeck class, as part of initialization, i call
[self cutDeckImageIntoCards]; // We don't get to execute this method
Call results in an error [PlayerDeck cutDeckImageIntoCards]: unrecognized selector sent to instance
Indeed, PlayerDeck does not have this method .. but why is it being called at all?
After looking at MasterDeck's initialization i added a few debugging statements:
static MasterDeck *gInstance = NULL;
+(MasterDeck *) instance {
#synchronized(self) {
if (gInstance == NULL) {
gInstance = [[self alloc] init];
}
}
return gInstance;
}
-(id) init {
if (gInstance != NULL) {
return gInstance;
}
// MasterDeck
self = [super init];
// PlayerDeck
if (self) {
// Lots of stuff
[self cutDeckImageIntoCards]
// Some more stuff
}
gInstance = self;
return gInstance;
}
Ok, so MasterDeck is PlayerDeck because' Deck thinks it is a PlayerDeck ... Deck confirms
Deck is created as follows:
static Deck *gInstance = NULL;
+(Deck *) instance {
#synchronized(self) {
if (gInstance == NULL) {
gInstance = [[self alloc] init];
}
}
return gInstance;
}
-(id) init {
if (gInstance != NULL) {
return gInstance;
}
self = [super init];
if (self) {
// Do something
}
NSLog(#"Deck thinks it's a %#", [[self class ]description]); // PlayerDeck
gInstance = self;
return gInstance;
}
So, again
#interface Deck : NSObject
Assuming above Singleton Implementation, why would Deck think it's actually a PlayerDeck?
So the way you've written this, if you create the PlayDeck instance first, then the Deck instance is now a PlayDeck.
And then if you go to create the MasterDeck instance, your call to [super init] dutifully returns that previous PlayDeck instance.
So why is Deck a singleton at all? Deck has two subclasses that are singletons, but are you really looking for a singleton Deck also?
At a minimum, you can make this sort of work by not setting gInstance from within each init. Let the class method do that. Just return self from each of the init's. Also, remove the check for gInstance being not null, other Deck's init will always return Deck's instance once you have an instance of Deck.
But beyond that, I would rethink this idea a bit. Hope that helps.
You'll probably want to separate your singleton class from the actual class.
Try implementing it as in this example,
+(id) instance {
static dispatch_once_t pred;
static MasterDeck *sharedInstance = nil;
dispatch_once(&pred, ^{
sharedInstance = [[MasterDeck alloc] init];
});
return sharedInstance;
}
What happens if you replace [[self alloc] init] with [[MasterDeck alloc] init]?
It may be that somehow self is PlayerDeck. To make sure, you could NSLog([self description]) just before calling + alloc.
Edit
I assume that the interesting part of the code you have above is part of the #implementation of MasterDeck. My suggestion would be to try a lot more logging, including determining what super and [self class] are before calling [super init], although these may be misleading...
Also, as a side note, I believe that you should call [self release] in init if you are returning the previously-created instance.
What does the [super init] method look like? Can you step into it, or is it the default initializer?
Edit 2
I think you're doing singletons wrong. If you initialize a PlayerDeck, that would create a singleton in Deck which is an instance of PlayerDeck. Then later, when you initialize a MasterDeck, calling [super init] will return the instance already created by the PlayerDeck.
It looks like you try to be clever, but fact is - often the computer is even smarter. :)
Your deck class caches an instance in gInstance - in fact, it looks like it may store a Deck, a PlayerDeck, or a MasterDeck, depending on what and how you call / instantiate first. After that, this very instance is returned by that init method.
I strongly suggest to get this code clean and readable. I bet there are numerous problems with this code - but your problem is already a good example. Your logic (which should be simple, I guess) can surely be implemented much easier.
Note - I'm not against singletons, but this sort of code stacking is an absolute no-go. It's hard to get more dependency logic into those lines. ;)

Singleton not initializing correctly

I have the following code that I am calling using this statement: SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease];
The problem is "sharedSQLiteDB" is not being called, but rather "allocWithZone" is, and therefore "checkIfDatabaseExists" is not being called, which is where the database is created.
I don't understand why... (i.e. what am I doing wrong?)
#import "SQLiteDB.h"
static SQLiteDB *sharedSQLiteDB = nil; // makes this a singleton class
#implementation SQLiteDB
#synthesize searchPaths, documentPath, databasePath, cDatabasePath;
#pragma mark Singleton Methods
+ (SQLiteDB *) sharedSQLiteDB {
if(!sharedSQLiteDB) {
sharedSQLiteDB = [[SQLiteDB alloc] init];
[sharedSQLiteDB checkIfDatabaseExists]; // check to see if d/b exists
}
return sharedSQLiteDB;
}
+(id)allocWithZone:(NSZone *)zone { // makes sure another instance is not allocated
if(!sharedSQLiteDB) {
sharedSQLiteDB = [super allocWithZone:zone];
return sharedSQLiteDB;
}
else {
return nil;
}
}
-(id)copyWithZone:(NSZone *)zone {
return self;
}
-(void) release {
// no-op
}
In the singleton pattern your use pattern should be:
SQLiteDB* db = [SQLiteDB sharedSQLiteDB];
They way you are calling it doesn't fit the singelton pattern. All access should be through your sharedSQLiteDB message.
In other words you shouldn't be initializing via typical Cocoa patterns (SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease]; is incorrect and full of problems) outside the scope of the class.
In a singleton using the default initialization pattern for the language (alloc/init for ObjC or the default constructor for C++) should generate a compile time error message since the constructor/init method should be protected.
See the Wikipedia entry. consult the Design Pattern C++ bible. There is even a version for Cocoa
Good luck.
It isn't executing your + (SQLiteDB *) sharedSQLiteDB method because you're not actually calling that method anywhere.
As you've seen, when you call [[SQLiteDB alloc] init], the allocWithZone method is called.
Change your call to be SQLiteDB *db = [SQLiteDB sharedSQLiteDB], which will call your checkIfDatabaseExists method in this case. However, if [[SQLiteDB alloc] init] is called somewhere else, then the checkIfDatabaseExists method call will still be skipped.
Maybe consider moving the checkIfDatabaseExists method into an init method so that it will be called for both your singleton method and your allocWithZone.
Honestly I don't see any error...
However I post the code I used to create a Singleton. It's from a source that now I don't remember the link... it's not my code.
static DataManager *_instance;
#implementation DataManager
+ (DataManager*)sharedInstance
{
#synchronized(self) {
if (_instance == nil) {
_instance = [[super allocWithZone:NULL] init];
// Allocate/initialize any member variables of the singleton class her
// example
//_instance.member = #"";
}
}
return _instance;
}
#pragma mark Singleton Methods
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedInstance]retain];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
I hope it helps
I highly recommend using the SyntesizeSingleton header file first created by Matt Gallagher.
Find the latest version (that I know about) here:
https://github.com/cjhanson/Objective-C-Optimized-Singleton
It makes creating a singleton dead simple.
Here's an example header:
#import <Foundation/Foundation.h>
#interface Example : NSObject {}
+(Example*)sharedExample;
#end
And the corresponding .m:
#import "FMUser.h"
#import "SynthesizeSingleton.h"
#implementation Example
SYNTHESIZE_SINGLETON_FOR_CLASS(Example);
#end
[Example sharedExample] is created for you. It's pretty sweet.

Is this valid code to create a NIB-instantiated singleton?

Assume that I instantiate an object of class MyGreatClass in my NIB (as usual by simply dragging an "Object" to the NIB and settings its class to MyGreatClass).
I want access to that instance anywhere in my codebase, without introducing coupling, i.e. without passing objects around like crazy, and without having an outlet to it in, say, [NSApp delegate]. (The latter would make AppDelegate terribly bulky with time.)
I ask: Is the following considered a good code to accomplish this?
//imports
static MyGreatClass *theInstance = nil;
#implementation MyGreatClass
+ (MyGreatClass *)sharedInstance
{
NSAssert(theInstance != nil, #"instance should have been loaded from NIB");
return theInstance;
}
- (id)init //waking up from NIB will call this
{
if (!theInstance)
theInstance = self;
return theInstance;
}
// ...
If this work as expected, I would after the app is loaded be able to access my instance via sharedInstance.
What do you think?
UPDATE: Hmm, on the second thought, the above init method maybe overkill. This is way simpler to think about:
- (id)init
{
NSAssert(!theInstance, #"instance shouldn't exist yet because only "
#"the NIB-awaking process should call this method");
theInstance = self;
return theInstance;
}
Again, what do you think?
The proper way to create a singleton is to override allocWithZone: to ensure another object cannot be created. Overriding init allows the new object to be created, but not initialized. It is thrown away because the init method simply ignores it and returns the object that has been created already. Here is how I would do it:
+ (MyGreatClass *)sharedInstance {
NSAssert(theInstance != nil, #"instance should have been created from NIB");
return theInstance;
}
+ (MyGreatClass *)allocWithZone:(NSZone *)zone {
if(theInstance) return theInstance;
return [[self alloc] init];
}
- (id)init {
if(theInstance) return theInstance;
if(self = [super init]) {
theInstance = self;
// other initialization
}
return self;
}
- (void)release {}
- (void)dealloc {
return;
[super dealloc]; // Prevent compiler from issuing warning for not calling super
}
I overrode release and dealloc to ensure that the singleton would not be deallocated. If you don't do this, you should retain and autorelease it in the sharedInstance method. If you want to support multithreading, you should also synchronize access to the theInstance variable.

Objective C init

Disclaimer, I'm new to Objective C. But I can't find this explained. I've seen two ways of implementing init:
- (id)init {
if ([super init]) {
return self;
} else {
return nil;
}
}
and
- (id)init {
if (self = [super init]) {
// do your init business here
}
return self;
}
so let's say i have:
myObj = [[MyObject alloc] init];
where MyObject class is a subclass of NSObject. in the second example, does init not return an initialized version of NSObject? so myObj would ... how would it know what it is? wouldn't it think it was an NSObject rather than a MyObject?
1) First version is just wrong. self should be always assigned with value returned by super initializer, because init<...> of super can return another object upon initialization (it's not unusual BTW). Second version is actually an 'official' way to implement init<...> methods.
2) 'wouldn't it think it was an NSObject rather than a MyObject'. myObj is instance of 'NSObject' and instance of 'MyObject'. It's the whole point of inheritance.
i just want to know, under the hood, how it does it.
It's pretty simple. 99.9% of all the classes you'll ever write will inherit from NSObject in some fashion. In the initializers, you're supposed to invoke super's designated initializer and assign it to self. Eventually, [super init] will be invoking -[NSObject init]. According to the documentation, that's implemented like this:
- (id)init {
return self;
}
So technically, if you inherit directly from NSObject, you're probably safe to not do the assignation of self = [super init];, because you know (and you're guaranteed) that this is equivalent to: self = self;, which is kind of pointless. Regardless, you should leave it in for consistency's sake.
However, once you start getting further down the inheritance chain, and especially when you're inheriting from opaque classes (ie, a class whose .m file you do not have), then things start getting shady. It is possible that you'll come across a class whose designated initializer looks something like this:
- (id) initWithFoo:(id)aFoo {
if ([aFoo isSuperFast]) {
[self release];
return [[SuperFastFooWrapper alloc] initWithFoo:aFoo];
}
self = [super init];
if (self) {
_foo = [aFoo retain];
}
}
This isn't as common, but it does happen. In this case, we're destroying self ([self release], to balance the alloc call that immediately preceded this) and instead returning a different object.

Accessing collection through KVC (to protect collection and be KVO compliant)

I have a class Test which has an array of Foos. I want to provide access to the Foos without exposing the ivar directly. I'm trying to make this KVC compliant (also to pave the way for KVO compliance). I have:
Test.h
#interface Test : NSObject
{
NSMutableArray *foos;
}
#property (readonly, copy) NSMutableArray *foos;
#end
Test.m
- (id) init
{
self = [super init];
if (self != nil)
{
foos = [[NSMutableArray array] retain];
}
return self;
}
- (NSMutableArray*) foos
{
return [self mutableArrayValueForKey:#"foos"];
}
- (NSUInteger)countOfFoos
{
return [foos count];
}
- (id)objectInFoosAtIndex:(NSUInteger)index
{
return [foos objectAtIndex:index];
}
- (NSArray *)foosAtIndexes:(NSIndexSet *)indexes
{
return [foos objectsAtIndexes:indexes];
}
- (void)insertObject:(id)key inFoosAtIndex:(NSUInteger)index
{
[foos insertObject:key atIndex:index];
}
- (void)insertFoos:(NSArray *)foosArray atIndexes:(NSIndexSet *)indexes
{
[foos insertObjects:foosArray atIndexes:indexes];
}
- (void)removeObjectFromFoosAtIndex:(NSUInteger)index
{
[foos removeObjectAtIndex:index];
}
- (void)removeFoosAtIndexes:(NSIndexSet *)indexes
{
[foos removeObjectsAtIndexes:indexes];
}
This enters an infinite loop when a client tries to add a Foo:
Test *test = [[Test alloc] init];
NSMutableArray *foos = test.foos;
[foos addObject:#"adding object"]; // infinite loop here
What am I doing wrong?
- (NSMutableArray*) foos
{
return [self mutableArrayValueForKey:#"foos"];
}
An accessor should not use KVC to get the value of the property being accessed; the idea is that KVC goes through the accessors, because the accessors are closer to the value than KVC is.
The correct implementation of foos should return a copy, mutable or otherwise, of the array. Here's how I'd do it:
- (NSArray *) foos
{
return [[foos copy] autorelease];
}
I would also make all of the accessors public. Anything that wants to mutate the array or randomly access elements at specific indexes can do so that way. It's still safe and encapsulated because they're going through your accessors, not directly accessing the array.
There's not really any reason to use the KVC protocol methods yourself unless you don't know what key you'll access at the time you write the code. For example, if you were writing the nib loader or the Cocoa Bindings system, you would use KVC.
The problem is that the proxy NSMutableArray returned by mutableArrayValueForKey: first has to get the real array, which it does through the "foos" method. Since that's the one that returns a proxy NSMutableArray it enters an infinite loop. One solution is to use another name:
- (NSMutableArray*) mutableFoos
{
return [self mutableArrayValueForKey:#"foos"];
}
I spent a very long time on this problem and wanted to get this through an accessor. I wanted to clarify in the answer for those coming in. This is what I did:
#property (nonatomic,readonly,getter=getTheFoos) NSMutableArray* foos;
Then obviously implemented:
- (NSMutableArray*)getTheFoos {
return [self mutableArrayValueForKey:#"foos"];
}
Had to be careful though, getFoos appears to be an (undocumented) KVC accessor, because this sends it into the same loop.
Then onto KVO:
Test* test= [[Test alloc] init];
NSObject* obj= [[NSObject alloc] init];
NSMutableArray* arrTheData= test.foos;
[test.foos insertObject:obj atIndex:0];
[arrFoos insertObject:obj atIndex:0];
arrFoos can read the updated, mutated array (it will have two objects in it), but inserting into it will not fire KVO. Somewhere on my adventures, I saw that the return from mutableArrayValueForKey: doesn't return an NSMutableArray*, but a subclass of it, which might be the cause of it.