2016-07-15 99 views
38

Sto imparando lo sviluppo iOS da un corso online e ogni volta fare una visualizzazione personalizzata (cella personalizzato vista tabella, la raccolta delle cellule vista, ecc) l'istruttore implementa sempre questo initializer:Che cosa è esattamente init coder aDecoder?

required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 

    } 

Perché proprio io ho sempre devo chiamare questo? Che cosa fa? Posso inserire proprietà all'interno di init?

+2

Questa risposta ti aiuterà http://stackoverflow.com/questions/24036393/fatal-error-use-of-unimplemented-initializer-initcoder-for-class Grazie –

+0

Se sottoclassi un oggetto che implementa 'NSCoding' quindi è necessario implementare questo inizializzatore, poiché è richiesto dalle classi che implementano 'NSCoding'. Devi almeno chiamare il metodo di superclasse init. Se 'NSCoder' contiene proprietà codificate per la tua classe, allora puoi usare questo metodo per recuperare quelle – Paulw11

+1

Prova a cercare. Questa domanda ha ricevuto risposta molte volte qui. – matt

risposta

7

L'obbligo di attuare tale inizializzatore è una conseguenza di due cose:

  1. Il Liskov substitution principle. Se S è una sottoclasse di T (ad esempio è una sottoclasse di ViewController), gli oggetti S (istanze di MyViewController) devono essere in grado di essere sostituiti in cui sono previsti oggetti T (istanze di ViewController).

  2. Gli inizializzatori non sono ereditati in Swift se eventuali inizializzatori sono definiti esplicitamente nella sottoclasse. Se viene fornito esplicitamente un inizializzatore, tutti gli altri devono essere esplicitamente forniti (che possono quindi chiamare semplicemente super.init(...)). Vedi this question per la logica. È in Java, ma si applica ancora.

al punto 1, tutto l'originale ViewController può fare, la sottoclasse MyViewController dovrebbe essere in grado di fare. Una cosa del genere è poter essere inizializzati da un dato NSCoder. Per il punto 2, la sottoclasse MyViewController non eredita automaticamente questa capacità. Pertanto, è necessario fornire manualmente l'inizializzatore che soddisfa questo requisito. In questo caso, è sufficiente delegare fino alla superclasse, per fare ciò che normalmente farebbe.

+0

Ha perfettamente senso che i costruttori non vengano ereditati: se si inizializza un'istanza della classe derivata utilizzando l'inizializzatore (ereditato) della classe base, le proprietà non ereditate che sono state appena definite ("aggiunte") dalla classe derivata non essere mai inizializzato. –

+0

In realtà, gli inizializzatori sono ereditati in Swift, dato che non si forniscono le proprie implementazioni di inizializzatore nella sottoclasse. Se le proprietà non ereditate recentemente definite hanno valori predefiniti, è possibile evitare di scrivere qualsiasi inizializzatore nella sottoclasse e semplicemente ereditare tutti gli inizializzatori della superclasse. Vedi [qui] (https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID222) – TheBaj

+0

@TheBaj Buon punto , Ho trascurato questo. – Alexander

45

Inizierò questa risposta dalla direzione opposta: cosa succede se si desidera salvare lo stato della vista su disco? Si tratta di una serializzazione . Il contrario è la deserializzazione - il ripristino dello stato dell'oggetto dal disco.

Il protocollo definisce NSCoding 2 metodi per serializzare e deserializzare gli oggetti:

encodeWithCoder(_ aCoder: NSCoder) { 
    // Serialize your object here 
} 

init(coder aDecoder: NSCoder) { 
    // Deserialize your object here 
} 

Allora perché è necessario in classe personalizzata? La risposta è Interface Builder. Quando si trascina un oggetto su uno storyboard e lo si configura, Interface Builder serializza lo stato di tale oggetto su disco, quindi deserializza quando lo storyboard viene visualizzato sullo schermo. È necessario comunicare a Interface Builder come eseguire tali operazioni. Per lo meno, se non aggiungi nuove proprietà alla sottoclasse, puoi semplicemente chiedere alla superclasse di fare il pacco e il disimballaggio per te, quindi la chiamata super.init(coder: aDecoder). Se la sottoclasse è più complessa, è necessario aggiungere il proprio codice di serializzazione e deserializzazione per la sottoclasse.

Questo è in contrasto con l'approccio di Visual Studio, che è quello di scrivere il codice in un file nascosto per rendere l'oggetto in fase di esecuzione.

+0

Perché non mettere tutto ciò che è in stato di attivazione da OnNib e dimenticare di usare 'init (coder aCoder: NSCoder)'? – Honey

+0

@Honey - in una parola, "a volte non puoi farlo". Tipicamente puoi ma non sempre. – Fattie

+0

@Fattie sono i dettagli di non farlo troppo complesso o inutile sapere? Se no ti spiego spiegando? – Honey