2012-08-06 13 views
7

Sono nuovo in Objective-C e sto provando a creare una classe singleton basata su Apple's documentation.super allocWithZone ha qualche dubbio nel concetto di classe singleton

+ (MyGizmoClass*)sharedManager 
{ 
    if (sharedGizmoManager == nil) { 
     sharedGizmoManager = [[super allocWithZone:NULL] init]; 
    } 
    return sharedGizmoManager; 
} 

+ (id)allocWithZone:(NSZone *)zone 
{ 
    return [[self sharedManager] retain]; 
} 

In questo codice sharedManager è un metodo statico che controllerà se oggetto di questa classe è presente. In tal caso restituirà l'oggetto creato precedentemente, altrimenti ne creerà uno nuovo.

Ho alcune domande:

  1. Se sharedManager è statico, come può per accedere super?

  2. Quando si stampa [super class] perché fornisce il nome della classe corrente?

  3. Perché [[super allocWithZone:NULL] init] restituisce l'oggetto di classe corrente?

  4. Se super è uguale a self qui perché non chiama la classe corrente allocWithZone:(NSZone *)zone?

+0

Puoi dare un'occhiata a [il mio post precedente sull'implementazione del modello singleton] (http://stackoverflow.com/questions/6912703/objective-c-static-field-and-implementing-singleton-pattern/6913036#6913036). Se hai inserito molti commenti nel codice di implementazione. Spero che questo aiuti –

+0

Perché stai allocando super? Non vuoi invece un'istanza di sé? –

+0

Questo è un documento incredibilmente vecchio. –

risposta

3

Le altre risposte, pur indicando una buona informazione in merito ai singleton, in realtà non hanno risposto alla tua domanda.La tua domanda è in realtà basata principalmente sull'orientamento degli oggetti, il fatto che tu faccia riferimento in modo specifico a un singleton è incidentale.

  1. ho risposto this question con riferimento al self, qui è la parafrasato, parte importante della risposta

    super ha senso in contesti livello di classe, ma si riferisce alla superclasse in sé, non è un istanza

  2. Anche questo mi stava buttando fuori. Chiesi this question e si è concluso:

    [super class] chiama il metodo super sulla istanza corrente (cioè self). Se il self avesse una versione sovrascritta, sarebbe chiamata e sarebbe diversa. Dal momento che non lo sostituisci, chiamare [self class] equivale a chiamare [super class].

  3. Sei sicuro che stia effettivamente restituendo un'istanza di questa classe? O lo stai assegnando a un'istanza sharedGizmoManager di questa classe?

  4. Super non è uguale a sé, ma alcuni dei metodi che hai chiamato: ad es. [super class] chiama la stessa implementazione del metodo che [self class] chiamerebbe.

+2

Penso che al # 2 manchi il marchio. super, una * parola chiave * che non può essere sovrascritta, invia messaggi alla superclasse. In un metodo statico + (che non sono veri metodi statici ma piuttosto metodi dinamici di classi * Class *) la superclasse è un * NSObject *. * Il metodo * class * NSObject * quando viene invocato con 'super' restituisce la sottoclasse, quindi' [self class] == [super-classe] 'in un metodo statico. –

+0

L'implementazione di NSObject ha il seguente aspetto: 'Classe + (Classe) { return self; } '- ' self' in questo caso, è la sottoclasse, perché è da dove viene inviato il messaggio. '+ (Class) superclass' avrà l'effetto desiderato, nel qual caso vuoi' [superclasse auto]; '(nota + metodo). – Ephemera

+0

@RiazRizvi, Sentitevi liberi di modificare le risposte! –

3

C'è un paio di cose da considerare qui. Innanzitutto, la guida sui concetti di base di Cocoa è un po 'obsoleta. Non tiene conto di alcune delle tecnologie attuali sviluppate da Apple, come Grand Central Dispatch e Automated Reference Counting. Il [retain] nel tuo metodo allocWithZone non si compilerebbe correttamente in un progetto abilitato ARC (dato che sei nuovo in Obj-C, sto facendo un presupposto anche tu sei nuovo per iOS/iPhone, e così tu dovrebbe leggere su quelle due tecnologie).

C'è una buona discussione di diversi modelli di progettazione Singleton oltre in questa discussione: What should my Objective-C singleton look like?

Tuttavia questo è un thread vecchio, e come tale non tiene conto automatizzata conteggio dei riferimenti (ho utilizzato Louis La risposta di Gerbang per anni e non funziona più nei progetti abilitati ARC.

per Arc-enabled progetti/file (sì ARC può essere attivata solo per i singoli file) - ci siamo spostati ad un Singleton che utilizza GCD e funziona abbastanza bene:

static YourClassName * volatile sharedInstance = nil; 

+ (YourClassName *)sharedInstance 
{ 
    static dispatch_once_t sharedInstanceToken; 
    dispatch_once(&sharedInstanceToken, ^{ 
     sharedInstance = [[YourClassName alloc] init]; 
    }); 
    return sharedInstance; 
} 

cosa sta succedendo qui? Bene, se dai un'occhiata allo GCD docs, vedrai che dispatch_once viene eseguito una sola volta durante l'intera vita di un'applicazione per un oggetto particolare. Come dicono i documenti, questo lo rende molto utile per creare singleton in un modo sicuro per i thread.

Inoltre, dichiariamo volatile il metodo sharedInstance, il che significa che il compilatore/runtime non deve mai provare a memorizzare una chiamata al metodo e deve sempre eseguire il codice all'interno. Questo assicura che chiamiamo sempre in GCD e che recuperiamo sempre l'oggetto che dovremmo.

Sto sorvolando un mucchio da quando sei nuovo a Obj-C, ma sicuramente dai un'occhiata a GCD, ARC, e poi una volta che hai una solida base in Obj-C, cercando nella cache di IMP , che è ciò che volatile impedisce di accadere.

+0

ottima risposta, recentemente sono passato a questo modo di creare singoletti, ma non avevo mai sentito parlare della parola volatile! –

+0

Sebbene tu fornisca buone informazioni sui singleton, essi mettono in dubbio solo i riferimenti casuali. La domanda è in realtà su oop e quale implementazione dei metodi sono chiamati. –

+3

"dichiariamo il metodo sharedInstance come volatile" - Ma stai dichiarando la variabile statica volatile, non il metodo. I metodi volatili non esistono in Objective-C e le chiamate ai metodi non vengono mai ottimizzate. Invece, dovresti spostare la variabile statica all'interno del metodo. Ciò garantisce che non venga mai raggiunto senza chiamare il metodo. – nschum

3

(1.) Che cos'è super in una 'funzione statica'? In Objective-C, i metodi + sono correttamente chiamati metodi classe, i metodi -metodi sono chiamati metodi di istanza. Questi metodi + non sono veri metodi statici perché Objective-C classes are themselves objects of an opaque type called Class. Quindi sia super e self sono definiti in + metodi. super invia messaggi alla superclasse di MyGizmoClass, ma quando chiamato da un metodo + super cerca un metodo + equivalente e quando viene chiamato da un metodo-super cerca un metodo corrispondente.
self a + metodi di MyGizmoClass restituisce MyGizmoClass che è un Classe, mentre in -metodi self è un puntatore ad una MyGizmoClass esempio.

(2.) Il metodo +class restituisce self.isa. Si [super class] invoca il superclasse di:+class metodo, tuttavia, quando self è passato fino a + metodi né il suo valore, né il suo tipo sono modificati (mentre self 's tipo è gettato alla superclasse quando è passata attraverso -metodi). Pertanto, quando un'implementazione del metodo +class sulla catena richiede self.isa, ottiene lo stesso valore, MyGizmoClass.
Per essere certi, è possibile verificare che super fa chiamare +class in superclassi derivando MyGizmoClass da un MyGizmoSuperClass dove è possibile inserire un override:

@interface MyGizmoSuperClass : NSObject 
    @end 
    @implementation MyGizmoSuperClass 
    +(Class) class { 
     NSLog(@"yes it calls MyGizmoSuperClass:class"); 
     return [super class]; 
    } 
    @end 
    @interface MyGizmoClass : MyGizmoSuperClass 
    +(Class) classviasuper; 
    @end 
    @implementation MyGizmoClass 
    +(Class) classviasuper { 
     return [super class]; //which version of class will super call? 
    } 
    @end 
    int main(int argc, char *argv[]) 
    { 
     NSLog(@"returned %@",[MyGizmoClass classviasuper]); 
    } 

stampe

sì chiama MyGizmoSuperClass: classe
restituito MyGizmoClass

(3.) Anche in questo caso super chiama la versione superclasse di allocWithZone ma il valore self passato al metodo punta ancora ad un MyGizmoClass, e dal momento che allocWithZone restituisce un oggetto della classe del destinatario, si ottiene un MyGizmoClass indietro.

(4.) È possibile verificare facilmente che super è diverso da self. Se si implementa [self allocWithZone:NULL] il codice chiamerà implementazione MyGizmoClass s' di allocWithZone e ciclo a tempo indeterminato. Con [super allocWithZone:NULL], viene chiamata la versione della superclasse.