在Swift 3中,SE-0025对访问权限进行了改进,其中:
fileprivate
:用于定义只能在当前文件中访问的符号;
private
:用于定义只能在当前作用域以及子作用域中访问的符号;
绝大多数情况,它们都可以正常工作,但在Swift 3发布近一年之后,开发者发现这样的划分忽略掉了下面这样的场景:
假设,我们有一个机器人类,它有一个表示当前电量的属性:
class Robot {
private var battery: Double = 0.5
}
在Swift 3里,如果我们要把充电的方法写在extension里,是无法通过编译的:
extension Robot {
func charge() {
battery = 1.0 // This will fail in Swift 3
}
}
因为extension并不在Robot定义的作用域内部,但是像上面这种功能分组又很常见,于是,在Swift 3里,面对这种问题,很多开发者都使用fileprivate来替代private:
class Robot {
// In Swift 3, sometimes we use `fileprivate`
// instead of `private` for a larger access
// scope.
fileprivate var battery: Double = 0.5
}
但这并不是十全十美的解决方案,因为我们还可以在定义Robot的文件中编写这样的代码:
let r = Robot()
r.battery = 1.0
很明显,我们不应该允许这样的行为。所以,严格意义上说,我们期望的private访问权限要同时满足两个限制:
只在一个类型的“定义范围”中使用,这个范围同时包含了定义本身,以及类型的extension;
所有的extension必须和类型定义在同一个文件中,以防止外部代码也可以直接访问private属性;
而这,就是Swift 4中,对private权限的改进,现在你可以在Robot的定义,以及同文件内的所有extension Robot中,愉快的访问battery属性了:
class Robot {
private var battery: Double = 0.5
}
extension Robot {
func charge() {
// This will sucess in Swift 4
battery = 1.0
}
}
let r = Robot()
// This still failed in Swift 4
r.battery = 1.0