Domanda

Ti chiamare questa implementazione di un multiton in Objective-C 'elegante'? Ho programmazione uso 'non consentito' di alloc e allocWithZone: perché la decisione di assegnare o non alloca la memoria deve essere fatto sulla base di una chiave.

Lo so per certo che ho bisogno di lavorare con solo due casi, quindi sto usando 'switch-case' invece di una mappa.

#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: non ho provato se questo funziona ancora, ma la sua compilazione in modo pulito:)

È stato utile?

Soluzione

Trovo singletons una cattiva idea e questo sembra circa quattro volte più orribile. Il codice è abbastanza complesso, si può essere sicuri di trascorrere un bel paio d'ore a caccia di bug sottili in esso e si sarà probabilmente mai stare tranquillo su di esso. Non va bene. Si dovrebbe buttare via questo abominio e collegare gli oggetti insieme in qualche altro modo che non richiede così tanto pensare.

Se ti piace modelli, è possibile utilizzare qualcosa di simile al modello di fabbrica per collegare i vostri oggetti. La fabbrica si occuperà della creazione di queste due istanze e passando ovunque sia necessario. E la fabbrica sarà molto più semplice di multiton:

@interface Factory : NSObject {
    Foo *foo1, *foo2;
}
@end

@implementation Factory

- (id) init {
    [super init];
    foo1 = [[Foo alloc] init];
    foo2 = [[Foo alloc] init];
    return self;
}

Naturalmente non c'è bisogno di creare entrambi i casi in una sola volta. Si può fare tutto quello che vuoi lì - cache, carico pigro, qualsiasi cosa. Il punto sta lasciando la gestione Foo durata fino alla fabbrica, separato dal codice Foo. Poi diventa molto più facile. ¶ Tutti gli altri oggetti che devono Foo verrà creato e cablata attraverso la fabbrica e riceveranno la loro Foo attraverso un setter:

@implementation Factory

- (id) wireSomeClass {
    id instance = [[SomeClass alloc] init];
    [instance setFoo:foo1];
    [instance setAnotherDependency:bar];
    return [instance autorelease];
}

Questo è tutto molto più semplice, allora il codice dalla tua domanda.

Altri suggerimenti

Non ignorare alloc. Il problema con l'override alloc per restituire un'istanza precedentemente allocato della classe, come si fa, è che quando + sharedInstance chiama [[multiton alloc] init] ... + alloc restituirà l'istanza precedente, quindi -init sarà ri-inizializzare! la pratica migliore è quella di ignorare -init, facendo la ricerca nella cache e chiamando [rilascio auto] prima di restituire l'istanza memorizzata nella cache.

Se sei davvero preoccupati per il costo di tale + alloc in più (non è molto), è anche fare la tua ricerca nella cache in + sharedInstance e quindi garantire che tutti i client accedere all'istanza attraverso + sharedInstance per evitare l'alloc supplementare.

Mozione d'ordine: come fai a sapere che avrete sempre e solo dispone di due istanze, o la necessità di avere due istanze? (O si desidera avere due istanze?) Che cosa, esattamente, è il punto di avere un "multiton"? (Ed è che anche una parola?)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top