2015-05-06 15 views
36

Sto cercando di capire l'uso della parola chiave required nelle classi Swift.Perché utilizzare gli inizializzatori richiesti nelle classi Swift?

class SomeClass 
{ 
    required init() { 
     // initializer implementation goes here 
    } 
} 

required non mi costringono a implementare il metodo a mio figlio di classe. Se voglio sovrascrivere l'inizializzatore designato required della mia classe genitore, devo scrivere required e non override. So come funziona ma non riesco a capire perché dovrei farlo.

Qual è il vantaggio di required? Per quanto ne so, lingue come C# non hanno qualcosa del genere e funzionano perfettamente con override.

+0

L'implementazione nelle sottoclassi non è necessaria a causa dell'ereditarietà, il che ha senso. Tuttavia, sto anche chiedendo il beneficio qui. Se una sottoclasse (che sostituisce ipoteticamente 'init()' ma non un inizializzatore richiesto) ottiene init da un processo che ha chiamato l'inizializzatore richiesto ereditato, e che l'inizializzatore richiesto successivamente chiama 'init()', non chiamerebbe la sottoclasse ' init sovrascritto e tutto è buono? - Io penserei che l'unica buona ragione sarebbe che l'inizializzatore richiesto ** non ** chiama 'init()' su se stesso, quindi l'override 'init()' non verrebbe mai chiamato. –

+1

Questo potrebbe essere interessante in questo contesto: [Protocol func che restituisce Self] (http://stackoverflow.com/questions/25645090/protocol-func-returning-self). –

risposta

57

In realtà è solo un modo per soddisfare il compilatore per assicurare che se questa classe dovesse avere sottoclassi, erediterebbe o implementerà lo stesso inizializzatore. Vi è dubbio su questo punto, a causa della regola che se una sottoclasse ha un proprio inizializzatore designato, nessun inizializzatore dalla superclasse viene ereditato. Pertanto è possibile che una superclasse abbia un inizializzatore e la sottoclasse non la per averla. required supera questa possibilità.

Una situazione in cui il compilatore ha bisogno di essere in questo modo soddisfatte coinvolge i protocolli, e funziona così:

protocol Flier { 
    init() 
} 
class Bird: Flier { 
    init() {} // compile error 
} 

Il problema è che se Uccello aveva una sottoclasse, che sottoclasse avrebbe dovuto implementare o ereditare init e non l'hai garantito. Marking Bird's init come required lo garantisce.

In alternativa, è possibile contrassegnare Bird come final, garantendo così l'inverso, vale a dire che non avrà mai una sottoclasse.

Un'altra situazione è dove si ha un metodo factory che può fare una classe o la sua sottoclasse chiamando lo stesso inizializzatore:

class Dog { 
    var name: String 
    init(name: String) { 
     self.name = name 
    } 
} 

class NoisyDog: Dog { 

} 

func dogMakerAndNamer(whattype: Dog.Type) -> Dog { 
    let d = whattype.init(name: "Fido") // compile error 
    return d 
} 

dogMakerAndNamer sta chiamando il init(name:) inizializzatore sul cane o un cane sottoclasse. Ma come può il compilatore essere sicuro che una sottoclasse avrà un inizializzatore init(name:)? La designazione required calma le paure del compilatore.

1

Secondo il documentation:

Write the required modifier before the definition of a class initializer to 
indicate that every subclass of the class must implement that initializer 

Quindi sì, richiesto costringe tutte le classi figlio per implementare questo costruttore. Tuttavia, questo non è necessario

if you can satisfy the requirement with an inherited initializer. 

Quindi, se avete creato le classi più complesse che non possono essere completamente inizializzati con un costruttore genitore, è necessario implementare il costruttore richiede.

Esempio dalla documentazione (con alcune cose aggiunto):

class SomeClass { 
    required init() { 
     // initializer implementation goes here 
    } 
} 

class SomeSubclass: SomeClass { 
    let thisNeedsToBeInitialized: String 
    required init() { 
     // subclass implementation of the required initializer goes here 
     self.thisNeedsToBeInitialized = "default value" 
    } 
} 
0

Se si sta tentando di aggiungere il proprio initialiser nella classe sub, allora devi seguire certe cose coloro che sono stati dichiarati in classe Super. Quindi assicurati di non dimenticare di implementare il metodo richiesto. Se dimentichi che il compilatore ti darà l'errore // fatal error, we've not included the required init() . Un altro motivo è che crea un insieme di condizioni che mai la sotto classe dovrebbe seguire, la sottoclasse sta definendo il proprio inizializzatore.

6

Desidero attirare l'attenzione su un'altra soluzione fornita da Required, a parte che Matt ha dato sopra.

class superClass{ 
    var name: String 
    required init(){ 
     // initializer implementation goes here 
     self.name = "Untitled" 
    } 
} 
class subClass: superClass { 
    var neakName: String = "Subclass Untitled" 

} 
let instanceSubClass = subClass() 
instanceSubClass.name  //output: "Untitled" 
instanceSubClass.neakName //output: "Subclass Untitled" 

come si può verificare nel precedente esempio, ho dichiarato required init() su superClass, init() inizializzazione di superClass ha ereditato di default su subClass, Così in grado di creare un'istanza di sottoclasse let instanceSubClass = subClass().

Tuttavia, si supponga di voler aggiungere un inizializzatore designato nella sottoclasse per assegnare il valore del tempo di esecuzione alla proprietà memorizzata neakName. Ovviamente è possibile aggiungerlo, ma ciò comporterà nessun inizializzatore dalla superClass sarà ereditato nella sottoclassella, Quindi se si crea un'istanza di subClass si creerà tramite il proprio inizializzatore designato come di seguito.

class superClass{ 
    var name: String 
    init(){ 
     // initializer implementation goes here 
     self.name = "Untitled" 
    } 
} 
class subClass: superClass { 
    var neakName: String = "Subclass Untitled" 
    init(neakName: String) { 
     self.neakName = neakName 
    } 
} 
let instanceSubClass = subClass(neakName: "Bobby") 
instanceSubClass.name  //output: "Untitled" 
instanceSubClass.neakName //output: "Bobby" 

Qui sopra, non sarà in grado di creare un'istanza di subClass semplicemente subClass(), Ma se si vuole che ogni sottoclassi di superClass devono avere la propria init() initializer per creare un'istanza diretta da subClass(). È sufficiente inserire la parola chiave required prima di init() in superClass, che ti costringerà ad aggiungere l'inizializzatore init() allo subClass, come indicato di seguito.

class superClass{ 
    var name: String 
    required init(){ 
     // initializer implementation goes here 
     self.name = "Untitled" 
    } 
} 
class subClass: superClass { 
    var neakName: String = "Subclass Untitled" 
    init(neakName: String) { 
     self.neakName = neakName 
    } 
} // Compiler error <------------ required `init()` must be provided by subClass. 
let instanceSubClass = subClass(neakName: "Bobby") 
instanceSubClass.name  //output: "Untitled" 
instanceSubClass.neakName //output: "Bobby" 

SO, utilizzare required parola chiave prima di inizializzazione sulla superclasse, quando si desidera che tutti devono sottoclassi sono state attuate required initializer della superclasse.

Problemi correlati