我不能在扩展中使用私有属性。我的扩展名在另一个文件中。
如何在扩展程序中使用私有属性?
答案 0 :(得分:11)
在您的类型扩展中使用属性的规则实际上与在其他任何地方使用该属性的规则不同。
如果属性声明为private
,则除了在声明范围之外的任何地方都不能使用它。这意味着即使在同一个文件中也没有。
如果属性声明为fileprivate
,则只能在声明的文件中使用它(并且通过该文件中的任何)。
如果属性声明为internal
(默认值),则只能在声明的模块中使用(并且通过该文件中的任何)。
如果属性声明为public
或open
,则模块内部以及模块外部的任何内容都可以使用它来导入声明它的模块。
没有办法以这样的方式声明变量:它可以被类型的扩展使用,但不能被类型之外的其他东西使用。这实际上并不是从Swift 2到Swift 3的变化。情况一直如此。您正在寻找的是其他语言所称的protected
。 Swift没有,也从未有过与其他语言相同的protected
。
最接近的是在一个文件中声明一个类型及其所有扩展,并禁止在该文件中声明任何其他类型或类型扩展。然后,您可以将属性标记为fileprivate
,并通过该文件中的扩展名使用它们。这仍然不允许在文件外部通过该类型的扩展来使用该属性,并且它不会阻止未来的开发人员在该文件中添加另一种类型或使用该属性的文件的扩展名。
答案 1 :(得分:3)
@nhgrif关于在Swift中缺少protected
有多痛苦是正确的,但是有一种解决方法。
用protocol
包装对象,并仅声明要公开的方法和属性。
例如
MyUtiltyClass.swift
protocol IMyUtiltyClass {
func doSomething()
}
class MyUtiltyClass : IMyUtiltyClass {
static let shared : IMyUtiltyClass = MyUtiltyClass()
/*private*/
func doSomethingPrivately() {
}
}
MyUtiltyClass + DoSomething.swift
extension MyUtiltyClass {
func doSomething() {
self.doSomethingPrivately()
print("doing something")
}
}
然后将对象视为接口类型,而不是直接将类/结构类型视为对象。
MyViewController.swift
class MyViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
MyUtiltyClass.shared.doSomething()
/*
//⚠️ compiler error
MyUtiltyClass.shared.doSomethingPrivately()
*/
}
}
快乐编码??
答案 2 :(得分:-1)
在扩展中编写私有变量不是一个好习惯(即使我们可以)。它会引入意想不到的错误。
如果您想访问该变量,您可以对该变量使用 private(set) 使其对外部世界只读。
例如
private(set) var myPrivateVariable:Int