Swift:设置协议的可选属性

Swift:设置协议的可选属性,swift,Swift,如何设置协议的可选属性?例如,UITRAITS有许多可选的读/写属性。当我尝试以下操作时,我得到一个编译错误(无法在“TextInputRaits”中分配给“keyboardType”): 通常,在访问协议的可选属性时,您会添加问号,但在指定值时,这不起作用(错误:无法指定此表达式的结果): 协议如下所示: protocol UITextInputTraits : NSObjectProtocol { optional var keyboardType: UIKeyboardType { g

如何设置协议的可选属性?例如,UITRAITS有许多可选的读/写属性。当我尝试以下操作时,我得到一个编译错误(无法在“TextInputRaits”中分配给“keyboardType”):

通常,在访问协议的可选属性时,您会添加问号,但在指定值时,这不起作用(错误:无法指定此表达式的结果):

协议如下所示:

protocol UITextInputTraits : NSObjectProtocol {
  optional var keyboardType: UIKeyboardType { get set }
}
这在斯威夫特是不可能的。引用自:

当访问或调用可选属性要求和返回值的可选方法要求时,将始终返回相应类型的可选值,以反映可选要求可能尚未实现的事实

因此,轻松获得可选值也就不足为奇了。但是,设置属性需要保证实现


一种解决方法是创建另一个协议,该协议符合第一个协议,但将该可选属性声明为强制属性。然后尝试将对象强制转换为新协议,如果转换成功,我们可以直接访问该属性

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)
}

我还演示了,如果你想要另一个例子,

< P>我会考虑做一个扩展,返回你的默认值,用于<代码> KiBooDype < /C>,让SETER不做任何事情。
extension UITextInputTraits {
   var keyboardType: UIKeyboardType { 
      get { return .default }
      set { /* do nothing */ } 
   }
}
这样,您就可以从属性声明中删除
可选的

protocol UITextInputTraits : NSObjectProtocol {
  var keyboardType: UIKeyboardType { get set }
}
或者,如果您愿意,可以将其设置为可选的返回类型,
var keyboardType:UIKeyboardType?
,并在扩展名中返回
nil
,而不是
。默认值


通过这种方式,您可以测试myObject.keyboardType==nil
以查看您的属性是否已实现。

以下是我为实现Swift 2.2兼容性而提出的建议:

@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)
        }
    }
}

本质上,您需要对可选属性执行“if/let绑定”,以确保它实际得到实现?如果它是nil,则封装对象没有实现它,但是您现在可以为它赋值,编译器将不再抱怨。

这只是更改了您创建的局部变量-它不会更改对象值。我在Swift 2.2中尝试了这一点,但是as?我似乎记得,协议实际上是根据其名称进行评估的。如果核心对象还没有实现“uitePuttRaitsWithKeyboardType”,那么它就不会通过。想知道你是如何做到这一点的……从Swift 2.2到Swift 4到Swift 5.3.2仍然不可能
protocol UITextInputTraits : NSObjectProtocol {
  var keyboardType: UIKeyboardType { get set }
}
@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)
        }
    }
}