爲 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 相似的東西提供默認值)
相關文章
相關標籤/搜索