在开发 iOS 应用时,我们需要对代码中的各种组件进行访问控制。为此,Swift 提供了多种访问控制级别来限制属性、方法和类等组件的访问范围,并提高代码模块化程度。
访问控制级别
Swift 中有五个访问控制级别,按照访问权限从高到低分别为:
- open:可被任何 module 访问,允许子类继承和重写,最高级别;
- public:可被任何 module 访问,但不允许子类继承和重写;
- internal:只能在当前 module 内部访问,是默认级别;
- fileprivate:只能在当前文件内部访问;
- private:只能在当前作用域内部访问,最低级别。
访问控制示例
下面的示例演示了如何使用 Swift 的访问控制语法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyClass {
fileprivate var filePrivateVar = 0
private func doSomething() {}
}
class MyInternalClass {
var internalVar = 0
func doSomething() {}
}
fileprivate class MyFilePrivateClass {
var filePrivateVar = 0
func doSomething() {}
}
private class MyPrivateClass {
var privateVar = 0
func doSomething() {}
}
在上面的示例中,我们定义了四个类,并分别使用了不同的访问控制级别。其中,MyClass
是一个公开类,filePrivateVar
属性的访问控制级别为 fileprivate
,doSomething()
方法的访问控制级别为 private
;MyInternalClass
是一个内部类,internalVar
属性和 doSomething()
方法的访问控制级别为 internal
;MyFilePrivateClass
是一个文件私有类,filePrivateVar
属性和 doSomething()
方法的访问控制级别为 fileprivate
;MyPrivateClass
是一个私有类,privateVar
属性和 doSomething()
方法的访问控制级别为 private
。
访问控制规则
Swift 访问控制规则如下:
- 访问级别可以针对类型、属性、方法、初始化器或者下标脚本等各种组件进行指定;
- 访问级别不能高于其所属模块的访问级别;
- 类型的访问级别会影响其成员的默认访问级别;
- 子类不能拥有高于父类的访问级别;
- 可以使用
public
或者open
级别来覆盖成员的默认访问级别; - 元素的访问控制规则遵循就近原则。
类型访问控制
在 Swift 中,可以通过以下方式指定类型的访问控制级别:
1
2
3
4
5
6
7
8
9
10
11
12
open class MyClass {
public var myPublicVar = 0
internal var myInternalVar = 0
fileprivate var myFilePrivateVar = 0
private var myPrivateVar = 0
open func myOpenMethod() {}
public func myPublicMethod() {}
internal func myInternalMethod() {}
fileprivate func myFilePrivateMethod() {}
private func myPrivateMethod() {}
}
在上面的示例中,我们使用 open
关键字指定了 MyClass
类的访问控制级别。同时,我们还对各种属性和方法进行了不同级别的访问控制。
函数参数的访问控制
在 Swift 中,函数的参数也可以使用访问控制,例如:
1
func hello(_ name: String, privacyLevel: Int) {}
在上面的示例中,name
参数没有指定访问控制级别,因此其默认为函数的访问控制级别。而 privacyLevel
参数则指定了访问控制级别为 Int
类型的访问控制级别。
枚举类型访问控制
在 Swift 中,枚举类型的访问控制级别可以通过以下方式指定:
1
2
3
4
5
public enum MyEnum {
case case1
case case2
case case3
}
在上面的示例中,我们使用 public
关键字指定了 MyEnum
枚举类型的访问控制级别。
子类和重写
子类和重写成员遵循以下规则:
- 子类不能拥有高于父类的访问级别。
- 重写成员必须和被重写成员有相同的访问控制级别或更高的访问控制级别。
- 重写成员不能低于其父类的访问控制级别。
- 子类可以使用
public
或open
级别来重写父类的成员,并且可以将访问控制级别提高到public
或open
级别。
在下面的示例中,我们定义了一个基类 MyBaseClass
和一个子类 MySubClass
,并对它们的属性和方法进行了不同的访问控制设置:
1
2
3
4
5
6
7
open class MyBaseClass {
fileprivate func doSomething() {}
}
class MySubClass: MyBaseClass {
override internal func doSomething() {}
}
在这个例子中,MyBaseClass
类的 doSomething()
方法的访问控制级别为 fileprivate
,而子类 MySubClass
通过 override
关键字重写了该方法,并将其访问控制级别提升到了 internal
级别。
访问控制和扩展
在 Swift 中,扩展可以添加新的属性、方法和下标脚本等成员。对于扩展中定义的成员,它们的访问控制级别取决于原始类型的访问控制级别。
例如,在下面的示例中,我们定义了一个名为 MyClass
的类,并针对该类添加了一个扩展:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyClass {
public var myPublicVar = 0
internal var myInternalVar = 0
fileprivate var myFilePrivateVar = 0
private var myPrivateVar = 0
public func myPublicMethod() {}
internal func myInternalMethod() {}
fileprivate func myFilePrivateMethod() {}
private func myPrivateMethod() {}
}
extension MyClass {
func myExtensionMethod() {}
}
在上面的示例中,扩展中定义的 myExtensionMethod()
方法的访问控制级别与 MyClass
原始类型的访问控制级别相同。
访问级别的继承与重写
在Swift中,可以通过继承和重写来改变实体的访问级别。通常情况下,子类不能高于父类的访问级别。如果子类想要复写父类的属性或方法,那么它们的访问级别必须相等或更高。
下面是一个例子:
1
2
3
4
5
6
7
8
open class SuperClass {
public var publicVar = 0
internal func internalMethod() {}
}
class SubClass: SuperClass {
override internal func internalMethod() {}
}
在上面的代码中,我们定义了一个公开类SuperClass
,它包含了一个公共变量和一个内部方法。我们还定义了一个子类SubClass
,它覆盖了SuperClass
的内部方法,但是它的访问级别仍然是内部级别。
访问控制的优缺点
访问控制可以提高代码的安全性和可维护性,但是它也会增加代码的复杂性,降低代码的灵活性。
优点:
- 提高了代码的安全性,防止误操作和非法修改。
- 提高了代码的可维护性,使得代码更易于理解和维护。
- 提高了代码的可重用性,使得不同的模块之间更易于交互和调用。
缺点:
- 增加了代码的复杂性,需要花费更多的时间和精力来设计和实现。
- 降低了代码的灵活性,有时可能需要调整访问级别来满足需求。
- 可能会引发一些意外的问题,例如继承和重写时可能会导致访问级别的矛盾。