2013-03-17 13 views
12

Ho letto molti thread e articoli di blog su come implementare un singleton in ogg-c, alcuni dei quali forse sono un po 'deprecati (anno 2010 o precedenti), e sembra che le persone abbiano opinioni diverse riguardo a questo problema ... Apple ha documentazione sull'implementazione di un singleton? Non riuscivo a trovarlo. Se così fosse, qualcuno potrebbe dirmi dove?Pattern singleton Objective-C in iOS 5+

Ho bisogno di un singleton per una classe che ha alcune variabili sia pubbliche che private. Attualmente, questa è l'implementazione che ho per tale classe:

@interface MySingleton() 
    @property (strong, nonatomic) NSString *state; 
@end 

@implementation MySingleton 

@synthesize state = _state; 
@synthesize count = _count; 

static MySingleton *sharedObject = nil; 

+ (MySingleton *)sharedInstance 
{ 
    static dispatch_once_t _singletonPredicate; 

    dispatch_once(&_singletonPredicate, ^{ 
     sharedObject = [[super allocWithZone:nil] init]; 
    }); 

    return sharedObject; 
} 

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

Dovrebbe essere questo il modo consigliato? E come devo inizializzare le variabili di istanza, pubbliche e private?

Un altro problema che vorrei chiarire su Singleton è: genererà una perdita di memoria? L'uso di singleton è effettivamente raccomandato in iOS?

Grazie

+0

Infatti ... funzionerebbe in iOS4? (Come una curiosità.) – Fattie

+0

E può essere utile, si noti la presentazione eccezionalmente semplice del codice nella risposta popolare qui: http://codereview.stackexchange.com/questions/19829/objective-c-singleton-implementation – Fattie

risposta

3

In Xcode, sotto 'Cerca documentazione' entrano Creating a Singleton Instance. Ci sono molti risultati (ma il link sopra, in fondo alla pagina, ha un codice di esempio).

+9

Do not utilizzare il codice in fondo a quella pagina leggermente. È esclusivamente per la creazione di un "rigoroso singleton" come si legge. Questi sono estremamente rari nel cacao. I singleton condivisi sono la norma e non richiedono la maggior parte di questo codice. Questo snippet di codice ha causato molta confusione tra i nuovi sviluppatori di Cocoa. Raccomando di ignorarlo; è improbabile che incontri casi in cui è utile. –

1

Sì, questo è il metodo consigliato. C'è solo una piccola differenza di come la utilizzo: definisco lo sharedObject come variabile statica all'interno del metodo + (MySingleton *)sharedInstance, perché non dovrebbe essere possibile accedere alla variabile da nessun'altra parte, quindi dal metodo getter.

E no, non si creerà una perdita di memoria. Quando la tua app viene terminata, tutta la memoria riservata utilizzata dalla tua app verrà comunque rilasciata e non ci saranno altre situazioni in cui un'istanza condivisa statica dovrebbe essere rilasciata. Nell'area pre-ARC era anche normale sovrascrivere il metodo release per impedire il rilascio accidentale dell'oggetto.

+0

Vuoi dire 'sharedObject' dovrebbe essere una variabile statica? –

+0

Oh, certo. Era solo un errore di battitura. Lo ha modificato. – miho

12

Quanto sopra è corretto, insieme al commento di @ miho relativo all'integrazione dell'oggetto statico all'interno del metodo sharedInstance. Ma non c'è motivo di ignorare lo +allocWithZone:. I single di ObjC sono generalmente "condivisi", non forzati. Sei libero di creare altre istanze di un "singleton". Se è illegale creare altre istanze, è necessario eseguire init eseguendo un NSAssert invece di ingannare il chiamante in +allocWithZone:. Se il tuo singleton è mutabile (e la maggior parte lo sono), non devi assolutamente ignorare lo +allocWithZone: in questo modo.

Un altro problema che vorrei chiarire su Singleton è: genererà una perdita di memoria?

No. Questo oggetto non verrà mai rilasciato, ma sarà sempre accessibile. Questa non è una perdita.

L'uso di singleton è effettivamente consigliato in iOS?

Sì, ed è uno schema molto comune, utilizzato in tutti i framework Cocoa. Detto questo, ci sono vari altri modelli che hanno iniziato a diventare in qualche modo popolari tra gli sviluppatori. L'iniezione di dipendenza sta suscitando un certo interesse, anche se non la vedo molto spesso nella pratica. Ridurre la dipendenza dai singleton può migliorare la testabilità e recentemente ho sperimentato come eliminare alcuni di essi nel mio codice con un certo successo. Ma hanno una lunga e orgogliosa storia a Cocoa, e non li considero un problema.

MODIFICA: si ha un bug effettivo nel codice. Dovresti chiamare [[self alloc] init], non [[super alloc] init]. Non c'è motivo per chiamare mai +allocWithZone:, basta usare +alloc. (Il tempo in cui ...WithZone: metodi erano utili è da tempo superato.)

+0

Non lo capisco completamente da solo, ma nel libro di BNR iOS, usano '[[super allocWithZone: nil] init]' e restituiscono '[self sharedInstance]' in '+ allocWithZone:'. La ragione fornita qui è che 'alloc' chiama solo' allocWithZone: 'che esegue l'allocazione effettiva. Usando '[super allocWithZone]' evita che il codice entri in circolo, chiamando il proprio metodo 'allocWithZone'. –

+2

ah. Quando esci da override di 'allocWithZone:' (che non dovresti quasi mai sovrascrivere), questo non sarà più un problema. –

+0

Grazie! E poi, le variabili dovrebbero essere inizializzate sovrascrivendo il metodo 'init', come nelle classi" regolari "? – AppsDev

0

Un po 'di avvertimento con GCD per single:

dispatch_once(&_singletonPredicate, ^{ 
     sharedObject = [[super allocWithZone:nil] init]; 
    }); 

se il metodo init per qualche motivo si rivolge direttamente o indirettamente l'oggetto Singleton, non ci sarà essere un punto morto. Per questo motivo credo che il modo più appropriato per scrivere un Singleton è attraverso il metodo

+ (void) initialize 

+1

Perché il metodo init deve accedere all'istanza singleton? Non riesco a immaginare un caso in cui ciò accadrebbe. '+ initialize' non è il modo più appropriato per scrivere singleton da quando è stato rilasciato GCD. (Era un buon modo prima di quello.) –

+0

Ciao, Rob :) Voglio sinceramente grazie per il tuo meraviglioso libro "Sviluppo iOS: spingendo i limiti", ne ho imparato un sacco! Bene, questo è successo in una delle mie app: il metodo init ha istanziato un'istanza di un'altra classe, e quell'altra istanza ha indirizzato l'oggetto singleton, prima che il dispatch_once finisse (che causa deadlock). Sì, lo so dal punto di vista del design non è molto buono :) – cpprulez

+0

Esattamente.Hai un problema di progettazione qui, non un problema a schema singolo. Probabilmente stai facendo troppo in init. Si potrebbe anche utilizzare un singleton che non è necessario. A volte le persone saltano troppo velocemente verso i single, quando sarebbe meglio passare semplicemente l'oggetto. –

0

sto ancora utilizzando il singoletto intestazione thingy da CocoaWithLove - può essere un po 'datato, ma ancora funziona come un fascino. Fondamentalmente fa lo stesso descritto come here riferendosi alla documentazione di Apples e suppongo che almeno la documentazione di Apple (bottom of this page) sia ancora valida. C'è gente che presume che rimarrà valida indefinitamente sinusoidale è la soluzione ufficiale suggerita da Apple.

+0

Ciao, sì, questo è ancora valido, tuttavia non è efficiente, poiché c'è un blocco ogni volta che si accede al singleton, anche se solo un thread sta tentando di accedervi. dispatch_once risolve questo problema. – cpprulez