2014-09-28 21 views
14

Come si imposta una proprietà facoltativa di un protocollo? Ad esempio, UITextInputTraits ha un numero di proprietà di lettura/scrittura opzionali. Quando provo il seguente ottengo un errore di compilazione (Impossibile assegnare a 'KEYBOARDTYPE' in 'textInputTraits'):Swift: impostazione di una proprietà opzionale di un protocollo

func initializeTextInputTraits(textInputTraits: UITextInputTraits) { 
    textInputTraits.keyboardType = .Default 
} 

Normalmente quando si accede a una proprietà facoltativa di un protocollo si aggiunge un punto di domanda, ma questo non funziona quando si assegna un valore (di errore: non è possibile assegnare al risultato di questa espressione):

textInputTraits.keyboardType? = .Default 

il protocollo si presenta come: (? ancora)

protocol UITextInputTraits : NSObjectProtocol { 
    optional var keyboardType: UIKeyboardType { get set } 
} 

risposta

9

E 'impossibile a Swift . Citato da un ADF thread:

Optional property requirements, and optional method requirements that return a value, will always return an optional value of the appropriate type when they are accessed or called, to reflect the fact that the optional requirement may not have been implemented.

So it's no surprise to get optional values easily. However, setting a property requires implementation to be guaranteed.

+0

Ancora impossibile da Swift 2.2 – adib

+0

Ancora impossibile da Swift 4 – Speakus

+0

E per una buona ragione. Usa 'opzionale func setSomething (_ :)'. – akashivskyy

3

Una soluzione è quella di creare un altro protocollo conforme al primo, ma che dichiarare che proprietà facoltativa come obbligatorio. Quindi per provare a trasmettere l'oggetto come nuovo protocollo e se il cast ha esito positivo, possiamo accedere direttamente alla proprietà.

protocol UITextInputTraitsWithKeyboardType : UITextInputTraits { 
    // redeclare the keyboardType property of the parent protocol, but this time as mandatory 
    var keyboardType: UIKeyboardType { get set } 
} 

func initializeTextInputTraits(textInputTraits: UITextInputTraits) { 
    // We try to cast ('as?') to the UITextInputTraitsWithKeyboardType protocol 
    if let traitsWithKBType = textInputTraits as? UITextInputTraitsWithKeyboardType { 
    // if the cast succeeded, that means that the keyboardType property is implemented 
    // so we can access it on the casted variable 
    traitsWithKBType.keyboardType = .Default 
    } 
    // (and if the cast failed, this means that the property is not implemented) 
} 

ho anche dimostrato che at the bottom on this SO answer Se volete un altro esempio di questa idea.

+0

Ho provato questo con Swift 2.2, ma il come? non sta prendendo - Mi sembra di ricordare che i protocolli sono effettivamente valutati dal loro nome. Se l'oggetto principale non ha implementato "UITextInputTraitsWithKeyboardType", allora non passerà. Ti chiedi come funziona ... –

6

Vorrei prendere in considerazione l'estensione di un valore restituito per keyboardType e il setter non fare nulla.

extension UITextInputTraits { 
    var keyboardType: UIKeyboardType { 
     get { return .Default } 
     set(new){ /* do nothing */ } 
    } 
} 

In questo modo è possibile rimuovere il optional dalla dichiarazione di proprietà.

protocol UITextInputTraits : NSObjectProtocol { 
    var keyboardType: UIKeyboardType { get set } 
} 

O, se si preferisce, si può fare di tipo di ritorno opzionale, var keyboardType: UIKeyboardType?, e restituire nil invece di .Default nell'estensione.

In questo modo, è possibile verificare per myObject.keyboardType == nil per verificare se la proprietà è stata implementata.

0

Quello che segue è quello che mi è venuta per la Swift 2.2 compatibilità:

@objc protocol ComponentViewProtocol: class { 
    optional var componentModel: ComponentModelProtocol? { get set } 
    optional var componentModels: [String:ComponentModelProtocol]? { get set } 
} 

class ComponentView: NSObject, ComponentViewProtocol { 
    var componentModel: ComponentModelProtocol? 
    ... 
    .. 
    . 
} 

class SomeCodeThatUsesThisStuff { 

    func aMethod() { 
     if var componentModel = componentView.componentModel { 
      componentModel = .... (this succeeds - you can make assignment) 
     } else if var componentModels = componentView.componentModels { 
      componentModels = .... (this failed - no assignment possible) 
     } 
    } 
} 

In sostanza è necessario eseguire un "se/lasciatevi vincolante" sulla proprietà facoltativa per assicurarsi che in realtà è implementato? Se è nulla, allora l'oggetto incapsulante non lo ha implementato, ma altrimenti ora puoi assegnarlo e il compilatore non si lamenterà più.

+0

Cambia semplicemente una variabile locale che hai creato - non cambia il valore degli oggetti. –

Problemi correlati