為 protocol 中屬性新增預設值
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 theget
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
.
給屬性設定預設值
給屬性設定預設值?這難道不簡單?
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
的假象。