2012-03-09 6 views
38

Quando si progetta una gerarchia di classi, a volte la sottoclasse ha aggiunto un nuovo metodo initWithSomeNewParam e sarebbe desiderabile disabilitare le chiamate al vecchio metodo init ereditato dalla superclasse.Il modo migliore per impedire ad altri programmatori di chiamare -init

Prima di tutto, ho letto la questione here, dove le alternative proposte sono o esclusione init un'eccezione in fase di esecuzione, o ignorare e impostare i valori predefiniti per le proprietà. Nel mio caso, non voglio fornire valori predefiniti, e voglio indicare chiaramente che il vecchio metodo non dovrebbe essere chiamato, e invece dovrebbe essere usato il nuovo metodo con parametri.

Quindi l'eccezione di runtime va bene, ma a meno che il codice non sia debuggato, non c'è modo per altri programmatori del team di notare che il vecchio metodo non è più destinato ad essere utilizzato.

Se ho ragione, non c'è modo di contrassegnare un metodo come "privato". Quindi, a parte l'aggiunta di commenti, c'è un modo per farlo?

Grazie in anticipo.

+0

Commenti ed eccezioni: non c'è molto altro da fare. –

risposta

103

è possibile contrassegnare in modo esplicito il tuo init come non disponibile nel file di intestazione:

- (id) init __unavailable; 

o:

- (id) init __attribute__((unavailable)); 

con la sintassi più tardi, si può anche dare una ragione:

- (id) init __attribute__((unavailable("Must use initWithFoo: instead."))); 

Il compilatore invia quindi un errore (non un avviso) se qualcuno tenta di chiamarlo.

+1

Questo fa il lavoro. Grazie! –

+2

+1 Non sapevo che esistesse. Ben fatto! – darvids0n

+2

molto bello, non lo sapevo neanche. –

0

initWith: Stuff e: OtherStuff non deve mai essere più di semplici costruttori.

In che modo efficace devono chiamare

self = [self init]; 

if(self) 
{ 
    self.stuff = Stuff; 
    self.other = OtherStuff; 
} 

così [init oggetto] restituisce sempre un oggetto in uno stato predefinito, e [oggetto initWithStuff: roba] restituirà l'oggetto nello stato predefinito con roba ignorato .

Fondamentalmente quello che sto ottenendo è, la sua cattiva pratica per scoraggiare [oggetto init] soprattutto quando qualcuno sottoclasse la sottoclasse in futuro ....

+0

Mi permetto di dissentire. Penso che ciò che vuole il manifesto abbia perfettamente senso (e l'ho fatto anche io, sebbene con le dichiarazioni di runtime). A volte non ha senso allocare un oggetto "vuoto" e non è possibile fornire valori predefiniti. Soprattutto se l'istanza è considerata immutabile o se si tratta di un cluster di classe. – DarkDust

+0

Sì, so che è una cattiva pratica, ma per alcune classi i valori predefiniti non hanno senso. –

+0

Se questo è il caso, allora è un motivo perfetto per usare + (class) classWithPredefinedStuff: (Stuff *) roba; –

-1

È possibile una sorta di contrassegnare un metodo come "privato" definendo un private extension nella classe.

Nel vostro .h:

@interface MyClassName 
- (void)initWithSomeNewParam:(id)param; 

Nella tua.m:

@interface MyClassName() 
- (void)init; 
@end 

Si potrebbe anche aggiungere un NSLog dichiarazione in modo che quando qualcuno è in esecuzione il progetto con una sessione di XCode allegato, vedranno l'uscita della console simile a "Si prega di non utilizzare init, utilizzare initWithSomeNewParam: invece. " Si noti che questo è l'approccio che Apple stessa ha storicamente adottato per le chiamate API deprecate (oltre che per la marcatura deprecata nei propri documenti).

+0

Non funziona con 'init' poiché è definito al livello' NSObject'. – DarkDust

+0

Mi permetto di dissentire. Il problema con questo metodo è più che contrassegnarlo come privato in questo modo ha * nessun effetto distinguibile *, poiché tutti sanno che gli oggetti possono 'init' dalla documentazione. E XCode lo mostrerà comunque nel completamento automatico del metodo per questo motivo, probabilmente. – darvids0n

4

da aggiungere a quanto @DarkDust pubblicato, è possibile in alternativa utilizzare UNAVAILABLE_ATTRIBUTE

- (id)init UNAVAILABLE_ATTRIBUTE; 

Questo genera un errore quando un utente tenta di chiamare init su un'istanza di questa classe.

Problemi correlati