2013-05-16 14 views
5

Ich habe eine Basis Store Klasse mit vielen Methoden, die alle Speicher erben. Jedes Geschäft ist ein Singleton. Gerade jetzt, jedes Geschäft legt seine eigene nahezu identische Methode:Objective-C - dynamischer Singleton-Initialisierer?

+ (Store *)instance { 
    static SubStore *store = nil; 
    if (!store) { 
     store = (SubStore *) [[super allocWithZone:nil] init]; 
     [store setupDefaults]; 
    } 
    return store; 
} 

Gibt es eine Möglichkeit, eine Singleton-Methode in einer Art und Weise zu fertigen, dass das Verfahren einfach auf die Basisklasse und von den Unterklassen geerbt hinzugefügt werden?

+1

Ich habe es versucht und nie einen Weg gefunden. Um threadsicher zu sein, sollten Sie statt des 'if (! Store)' einen 'dispatch_once'-Block verwenden. – Kevin

+0

Ich folgte Buch-Code. Ich werde in dispatch_once schauen. –

Antwort

2

Anstatt einen Speicher static SubStore * store = nil; zu verwenden, könnten Sie einen NSMutableDictionary verwenden, der Klassennamen als Schlüssel verwendet.

Kurz:

#import <Foundation/Foundation.h> 

@interface MONStore : NSObject 
- (NSString *)nameOfMostPopularItem; 
@end 

@implementation MONStore 

+ (instancetype)sharedStore 
{ 
    // lazy population - not thread safe 
    static NSMutableDictionary * stores = nil; 
    if (nil == stores) { 
     stores = [NSMutableDictionary new]; 
    } 
    NSString * key = NSStringFromClass([self class]); 
    if (nil == [stores objectForKey:key]) { 
     [stores setObject:[self new] forKey:key]; 
    } 
    return [stores objectForKey:key]; 
} 

- (NSString *)nameOfMostPopularItem 
{ 
    return nil; 
} 

@end 

@interface MONMusicStore : MONStore 
@end 

@implementation MONMusicStore 
- (NSString *)nameOfMostPopularItem { return @"Guitar Strings"; } 
@end 

@interface MONPetStore : MONStore 
@end 

@implementation MONPetStore 
- (NSString *)nameOfMostPopularItem { return @"Puppies"; } 
@end 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     NSLog(@"--- Shopping List ---\nMusic Store:\n\t%@\n\nPet Store:\n\t%@\n", 
        [MONMusicStore sharedStore].nameOfMostPopularItem, 
        [MONPetStore sharedStore].nameOfMostPopularItem 
        ); 
    } 
    return 0; 
} 

... nicht, dass ich jemals in meinem Programm tun würde.

+0

Was würden Sie stattdessen verwenden? –

+0

@StefanKendall Ich bin einer dieser Typen, die über Singletons murren/schreckt;) – justin

5

Stick mit einfach/dumm, aber verwenden Sie dispatch_once.

Sobald Sie versuchen, es generisch zu machen, wird es komplex. Und Buggy.

Die sharedInstance-Methode mit expliziter Klassenbenennung ist offensichtlich und es ist unwahrscheinlich, dass Sie sie mehr als einige Male in Ihrem Projekt wiederholen.

Wenn Sie jedoch viele Unterklassen der einen Klasse haben, wechseln Sie zu einem Bezeichnermodell. I.e. Ein Cache auf der abstrakten Speicherklasse, der Instanzen nach Bezeichnern suchen kann.


Ich vermeide entweder +initialize oder, schlimmer noch, +load für eine solche Initialisierung. Beide sind nicht-deterministisch, da ihre Reihenfolge der Ausführung in Bezug auf andere Subsysteme in Ihrer App ziemlich variabel sein kann mit scheinbar harmlosen Änderungen.

Viel besser, vollständig deterministische Initialisierung zu haben. Fügen Sie in Ihrem applicationDidFinishLaunching: (oder einem der anderen) ein Callout hinzu, das dieses bestimmte Subsystem in Ihrer App explizit initialisiert. Es ist einfach zu folgen, sowohl in der Deklaration als auch in der Verwendung explizit, und wird das Verhalten auf merkwürdige Weise nicht ändern, wenn sich Ihre Codebasis entwickelt.

+0

Ich habe diesen Initialisierungscode oft in '+ initialize' gesetzt. Die ObjC-Laufzeit sorgt dafür, dass die Methode nur einmal aufgerufen wird. – zneak

+3

@zneak Das ist nicht ganz richtig. Wenn Sie Klasse A mit einer 'initialize'-Methode und eine Klasse B, die A erweitert und Klasse B keine' initialize'-Methode implementieren, dann wird die 'initialize'-Methode der Klasse A zweimal aufgerufen - einmal, wenn A zuerst ist referenziert und wenn B zum ersten Mal referenziert wird. – rmaddy

+0

'+ load' wird nur einmal pro Klasse/Kategorie aufgerufen. – nielsbot