首先放個簡單的Playground做下示範。
普通 protocol 中的 get set
protocol
中屬性可以宣告為{ get }
或者{ get set }
。大多數人第一眼肯定覺得{ get }
是約束為 read-only 屬性,{ get set }
是約束為 read-write 屬性。但是在protocol
中這些約束都是最小約束,也就是說{ get }
屬性至少需要是 readable 的,至於它是否 writable 並不作要求;{ get set }
則明確的指出了屬性必須是可讀寫,但是官方文件說明了,用{ get set }
宣告的屬性,不能在遵守該協議的型別中被實現為let
屬性。
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
andset
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 theget
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.
給屬性設定預設值
給屬性設定預設值?這難道不簡單?
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 property
。
所以如果想要重新賦值,則該屬性必須是{ get set }
的,可給{ get set }
屬性提供預設值也比較尷尬:
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
屬性重新賦值並不會被儲存下來!
話說這個時候,我們是不是該聯想一下屬性和例項變數的關係 :)
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 的 protocol 中的 get set
上面提到蘋果文件指明瞭{ get set }
宣告的屬性不能被實現為let
。但是因為component
提供了預設值,那麼該{ get set }
屬性就可以不被實現,同時類可以宣告一個同名同型別的let
屬性覆蓋協議中的屬性,就造成了{ get set }
屬性可以被宣告為let
的假象。
總結一下可以被宣告的屬性型別
{ get }
屬性:- read-only 計算屬性
- read-wirte 計算屬性
- var 儲存屬性(儲存屬性不能被重新賦值)
- let 儲存屬性
{ get set }
屬性:- read-wirte 計算屬性
- var 儲存屬性
- let 儲存屬性(需要用 component 類似的東西提供預設值)