为 protocol 中属性添加默认值

首先放个简单的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 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的假象。

总结一下可以被声明的属性类型

  • { get }属性:
    • read-only 计算属性
    • read-wirte 计算属性
    • var 存储属性(存储属性不能被重新赋值)
    • let 存储属性
  • { get set }属性:
    • read-wirte 计算属性
    • var 存储属性
    • let 存储属性(需要用 component 类似的东西提供默认值)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值