2012-10-30 8 views
9

Sto cercando indicazioni generali su come gestire questa situazione. Ecco un esempio specifico.Cosa succede se una classe non ha un inizializzatore designato come documento?

Sto sottoclassi UIImageView e voglio sovrascrivere initWithImage per aggiungere il mio codice di inizializzazione dopo aver avuto la stessa super classe stessa con l'immagine fornita.

Tuttavia, non esiste alcun inizializzatore designato per UIImageView, quindi quale inizializzatore di super classe dovrei chiamare per garantire che la mia sottoclasse sia inizializzata correttamente?

Se una classe non designa un inizializzatore, devo:

  1. Si supponga che è sicuro di chiamare uno dei (UIImageView) inizializzatori della classe?
  2. Guardare alla super classe (UIView) per l'inizializzatore designato?

In questo caso sembra # 1 sarebbe la risposta, come ha senso effettuare le seguenti operazioni nel mio initializer override:

- (id)initWithImage:(UIImage *)image 
{ 
    self = [super initWithImage:image]; 
    if (self) { 
     // DO MY EXTRA INITIALIZATION HERE 
    } 
    return self; 
} 
+0

Mi sembra buono. Stai chiamando l'inizializzatore della superclasse. Qual'è il problema? Objective-C non fornisce un meccanismo per chiamare l'inizializzatore di una superclasse designata. (AFAIK) –

+0

UIImageView sarebbe la tua superclasse. Puoi chiamare (con 'super') qualsiasi inizializzatore valido di quella classe, inclusi gli inizializzatori che può ereditare (anche se alcuni di essi potrebbero non avere senso). –

+3

Questo funziona davvero bene, ma la mia domanda è più generale. La mia comprensione è che una sottoclasse dovrebbe sempre chiamare l'inizializzatore designato della super-classe, ma come faccio a sapere qual è l'inizializzatore designato se non è documentato? È sicuro chiamare qualsiasi inizializzatore nella super classe se nulla è contrassegnato come "designato"? – techsMex

risposta

5

UIImageView ha due inizializzatori, quindi si consiglia di fare in modo che la sottoclasse gestisce entrambi questi percorsi di inizializzazione.

Si potrebbe semplicemente dichiarare che -initWithImage: è l'inizializzatore designato e tutti gli altri inizializzatori non sono supportati.

Inoltre, è possibile implementare -initWithImage:highlightedImage: e generare un'eccezione per indicare che non è supportato.

In alternativa, è possibile dichiarare -initWithImage:highlightedImage: come inizializzatore designato e chiamare -initWithImage: l'inizializzatore designato.

Oppure, è possibile che venga chiamato l'inizializzatore -initWithImage: indipendentemente dal fatto che la classe sia inizializzata con -initWithImage: o -initWithImage:highlightedImage:.

+0

Darren, hai affermato che UIImageView ha 2 inizializzatori, ma come faccio a sapere qual è l'inizializzatore designato di UIImageView? o entrambi agiscono come inizializzatori designati se nessuno dei due è contrassegnato come "designato"? – techsMex

+0

UIImageView non ha un inizializzatore designato (forse perché il secondo inizializzatore non è stato aggiunto fino a iOS 3.0). Se così fosse, allora questo è l'inizializzatore che normalmente sovrascriverebbe e che coprirebbe tutte le basi. Ma dal momento che non ha un inizializzatore designato, probabilmente vuoi gestire entrambi gli inizializzatori e indirizzarli entrambi al tuo inizializzatore designato. Altrimenti, se qualcuno inavvertitamente chiama un inizializzatore che non supporta, ciò potrebbe produrre bug difficili da rintracciare. – Darren

+0

@Darren - OK, apparentemente stai usando "designato" in questo caso per indicare il metodo 'init' che è descritto nelle specifiche come" genitore "(il mio termine) degli altri metodi' init' della classe. Per esempio ci può essere un metodo 'initWithX:' e un metodo 'initWithX: andY:'. Comunemente il primo (che è un metodo di "convenienza") chiamerebbe il secondo, quindi è sufficiente sovrascrivere il secondo metodo. La specifica può o non può dirti questo. Altrimenti, è necessario sovrascrivere tutti i metodi 'init' che * potrebbero * essere chiamati quando si utilizza la classe, ma se si sa che solo uno viene usato, basta sovrascriverlo. –

1

Ogni classe che deriva da NSObject ha il metodo init come un inizializzatore che eseguirà il processo di inizializzazione per quell'oggetto. Quindi, se non sei sicuro, puoi sempre usare self = [super init] nel tuo inizializzatore personalizzato. Considerando che lo UIImageView ha due inizializzatori forniti da Apple, potrebbe essere necessario sostituirli entrambi o lanciare un'eccezione all'utente che non possono utilizzare questo metodo (Non consigliato).

Per esempio: -

- (id)initWithCustomParam:(NSString *)param { 

    if (self = [super init]) { 
     self.myparam = param; 
    } 
    return self; 
} 

E poi si può attuare altre inizializzatori come,

- (id)initWithImage:(UIImage *)image { 

    if (self = [self initWithCustomParam:@"default value"]) { 
     self.image = image; 
    } 
    return self; 
} 

o definire,

- (id)initWithImage:(UIImage *)image customParam:(NSString *)string { 

    if (self = [self initWithCustomParam:string]) { 
     self.image = image; 
    } 
    return self; 
} 
4

documentazione UIImageView è terribile. Mostra due inizializzatori ma puoi entrare in situazioni in cui nessuno di loro viene chiamato. Ad esempio, sto usando IB e solo initWithCoder: viene chiamato.

- (id)init 
{ 
    return [super init]; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    return [super initWithCoder:aDecoder]; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    return [super initWithFrame:frame]; 
} 

- (id)initWithImage:(UIImage *)image 
{ 
    self = [super initWithImage:image]; 
    return self; 
} 

- (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage 
{ 
    self = [super initWithImage:image highlightedImage:highlightedImage]; 
    return self; 
} 

L'unico modo corretto di sottoclasse UIImageView è quello di creare una sottoclasse TUTTI initializers E ogni sottoclasse può chiamare solo di inizializzazione di un genitore con lo stesso nome. Per esempio:

subclass -init può chiamare UIImageView -init ma non può chiamare UIImageView -initWithCoder:.

Sì, è un vero dolore che non vi è alcuna designazione.

+0

questo è un problema comune - se l'oggetto viene caricato da un NIB, verrà chiamato '-initWithCoder:'. Quindi devi sovrascriverlo anche tu. – nielsbot

+3

Non credo che questo approccio sia sicuro. Poiché nessuno degli inizializzatori è stato designato, non puoi sapere che una chiamata a 'super' non richiamerà l'override di un altro. Se non fossero banali, allora potresti lavorare due volte e questo non dovrebbe essere fatto due volte. (Se fossero banali, non applicheresti nessuno di loro.) –

+0

@KenThomases grazie Ho aggiornato per questa sfumatura –

2

Il pericolo quando non c'è un inizializzatore designato è che qualsiasi inizializzatore che si potrebbe invocare potrebbe fare il suo lavoro in termini di uno degli altri inizializzatori. In tal caso, potrebbe accidentalmente chiamare uno dei tuoi override, che non funzionerà come previsto.

Se la classe ha esattamente un inizializzatore ed è un override di un inizializzatore di una superclasse, è sicuro che invochi l'inizializzatore su cui è stato eseguito l'override. Questo perché non ci sono possibilità che il super inizializzatore si reinserisca (direttamente o indirettamente) da solo, quindi non c'è alcuna possibilità che possa rientrare nel proprio override.

La classe potrebbe anche implementare qualsiasi numero di inizializzatori finché nessuno di loro hanno lo stesso nome di qualsiasi di quelli delle superclassi. Poiché i tuoi nomi sono unici, non c'è alcuna possibilità che nessuno degli inizializzatori della superclasse li chiamerà accidentalmente.

1

Un approccio alternativo è quello di essere pigri. È possibile utilizzare metodi come viewDidLoad o viewDidMoveToSuperview per eseguire alcune impostazioni. Dipende davvero da quando la configurazione è importante.

+0

Questo non risponde affatto alla domanda. –

+0

Certo che lo fa. È un posto dove sistemare pigramente. – uchuugaka

Problemi correlati