为 protocol 中属性添加默认值

首先放个简单的Playground作下示范。html

普通 protocol 中的 get set

protocol中属性能够声明为{ get }或者{ get set }。大多数人第一眼确定以为{ get }是约束为 read-only 属性,{ get set }是约束为 read-write 属性。可是在protocol中这些约束都是最小约束,也就是说{ get }属性至少须要是 readable 的,至于它是否 writable 并不做要求;{ get set }则明确的指出了属性必须是可读写,可是官方文档说明了,用{ get set }声明的属性,不能在遵照该协议的类型中被实现为let属性。git

The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements.github

给属性设置默认值

给属性设置默认值?这难道不简单?swift

protocol FloatingViewProtocol {
    var isDraggable: Bool { get }
}

extension FloatingViewProtocol {
    var isDraggable: Bool {
        return true
    }
}

class FloatingView: FloatingViewProtocol {
    var isDraggable = false
}
复制代码

给一个{ get }属性提供默认值,只须要在extension中一个return就搞定,确实很简单,可是这里出现了个问题,在尝试给FloatingView对象isAutoAdsorb属性从新赋值时会报错,提示isDraggable is a get-only propertyide

因此若是想要从新赋值,则该属性必须是{ get set }的,可给{ get set }属性提供默认值也比较尴尬:ui

protocol FloatingViewProtocol {
    var isDraggable: Bool { get set }
}

extension FloatingViewProtocol {
    var isDraggable: Bool {
        get { return true }
        set { }
    }
}

class FloatingView: FloatingViewProtocol { }
复制代码

如上确实提供了默认值,可是set { }实在谈不上优雅,而且还有个致命的问题,isDraggable不是个存储属性。若是FloatingView在声明时采用了默认的isDraggable值,那么给FloatingView对象isAutoAdsorb属性从新赋值并不会被保存下来!spa

话说这个时候,咱们是否是该联想一下属性和实例变量的关系 :)code

class FloatingViewProtocolComponent {
    var isDraggable = true
    public init() {}
}

protocol FloatingViewProtocol {
    var component: FloatingViewProtocolComponent { get }
    var isDraggable: Bool { get set }
}

extension FloatingViewProtocol {
    var isDraggable: Bool {
        get { return component.isDraggable }
        set { component.isDraggable = newValue }
    }
}

class FloatingView: FloatingViewProtocol {
    var component = FloatingViewProtocolComponent()
}
复制代码

经过一个component属性来实现相似实例变量的功能,操做仍是有点骚。component

实现 component 的 protocol 中的 get set

上面提到苹果文档指明了{ get set }声明的属性不能被实现为let。可是由于component提供了默认值,那么该{ get set }属性就能够不被实现,同时类能够声明一个同名同类型的let属性覆盖协议中的属性,就形成了{ get set }属性能够被声明为let的假象。orm

总结一下能够被声明的属性类型

  • { get }属性:
    • read-only 计算属性
    • read-wirte 计算属性
    • var 存储属性(存储属性不能被从新赋值)
    • let 存储属性
  • { get set }属性:
    • read-wirte 计算属性
    • var 存储属性
    • let 存储属性(须要用 component 相似的东西提供默认值)
相关文章
相关标签/搜索