mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 04:17:17 +00:00
203 lines
5.2 KiB
Markdown
203 lines
5.2 KiB
Markdown
# Swift 访问控制
|
||
|
||
## 访问控制
|
||
|
||
在访问权限控制这块,Swift 提供了5个不同的访问级别(以下是从高到低排列, 实体指被访问级别修饰的内容)
|
||
|
||
- open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
|
||
- public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
|
||
- internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
|
||
- fileprivate:只允许在定义实体的源文件中访问
|
||
- private:只允许在定义实体的封闭声明中访问
|
||
|
||
绝大部分实现默认都是 internal
|
||
|
||
|
||
|
||
## 使用准则
|
||
|
||
各种 case 如下:
|
||
|
||
- 变量类型 >= 变量
|
||
|
||
```swift
|
||
fileprivate class Person {
|
||
func sayHi() {}
|
||
}
|
||
internal var p:Person = Person() // Variable cannot be declared internal because its type uses a fileprivate type
|
||
class Dog {
|
||
func sepak() {
|
||
p.sayHi()
|
||
}
|
||
}
|
||
```
|
||
|
||
编译器报错:`Variable cannot be declared internal because its type uses a fileprivate type`。 访问权限前后冲突了。变量 p 被声明为 internal,也就是其他类中也可以使用该对象。但 Person 类被 fileprivate 修饰了,也就是只可以在定义该类的文件中使用。所以会冲突
|
||
|
||
- 参数类型、返回值类型 >= 函数
|
||
|
||
- 父类 >= 子类
|
||
|
||
- 父协议 >= 子协议
|
||
|
||
- 原类型 >= typealias
|
||
|
||
```swift
|
||
class Person {}
|
||
fileprivate typealias People = Person // 编译通过
|
||
public typealias People = Person // Type alias cannot be declared public because its underlying type uses an internal type
|
||
```
|
||
|
||
`Person` 默认是 internal,所以 typealias 的权限修饰符需要小于等于 internal。
|
||
|
||
- 原始值类型、关联值类型 >= 枚举类型
|
||
|
||
```swift
|
||
// 编译通过
|
||
typealias OwnInt = Int
|
||
typealias OwnString = String
|
||
internal enum DataKind {
|
||
case int(OwnInt)
|
||
case string(OwnString)
|
||
}
|
||
// 编译失败
|
||
fileprivate typealias OwnInt = Int
|
||
fileprivate typealias OwnString = String
|
||
|
||
public enum DataKind {
|
||
case int(OwnInt) // Enum case in a public enum uses a fileprivate type
|
||
case string(OwnString) // Enum case in a public enum uses a fileprivate type
|
||
}
|
||
|
||
```
|
||
|
||
- 定义类型 A 时用到的其他类型 >= 类型A
|
||
|
||
- 元祖类型:元祖类型的访问级别是所有成员类型最低的那个(木桶原理)
|
||
|
||
```swift
|
||
internal struct Dog {}
|
||
fileprivate class Person {}
|
||
|
||
internal var data1:(Dog, Person) // Error:Variable cannot be declared internal because its type uses a fileprivate type
|
||
fileprivate var data1:(Dog, Person)
|
||
private var data2:(Dog, Person)
|
||
```
|
||
|
||
看似规则比较多,实际上就是对「一个实体不可以被更低访问级别的实体定义」的解释。
|
||
|
||
|
||
|
||
类型的访问级别会影响成员(属性、方法、初始化器、下标)、嵌套类型的默认访问级别
|
||
|
||
- 一般情况下,类型为 fileprivate、private,那么成员、嵌套类型默认也是 private、fileprivate
|
||
- 一般情况下,类型为 internal、public,那么成员、嵌套类型默认也是 internal
|
||
|
||
|
||
|
||
测试:
|
||
|
||
```swift
|
||
// 编译不通过
|
||
class TestClass {
|
||
private class Person {}
|
||
fileprivate class Student : Person {} // Class cannot be declared fileprivate because its superclass is private
|
||
}
|
||
|
||
// 编译通过
|
||
private class Person {}
|
||
fileprivate class Student : Person {}
|
||
```
|
||
|
||
当 fileprivate、private 都写在文件的全局作用域时,访问权限是一样的。
|
||
|
||
|
||
|
||
|
||
|
||
## getter、setter
|
||
|
||
getter、setter 默认自动接收他们所属换的访问级别
|
||
|
||
可以给 setter 单独设置一个比 getter 权限更低的访问级别,用以限制写权限
|
||
|
||
```swift
|
||
private(set) var num = 10
|
||
class Person {
|
||
private(set) var age = 0
|
||
init(age: Int = 0) {
|
||
self.age = age
|
||
}
|
||
public var weight: Int {
|
||
set {}
|
||
get { 10 }
|
||
}
|
||
|
||
}
|
||
|
||
var p = Person(age: 10)
|
||
//print(p.age)
|
||
//p.age = 20
|
||
print(num)
|
||
num = 20
|
||
print(num)
|
||
```
|
||
|
||
|
||
|
||
## 初始化器
|
||
|
||
- 如果一个 public 类,想在另一个模块调用编译生成的默认无参初始化器,必须显示提供 public 的无参初始化器(因为 public 类的默认初始化器是 internal 级别的)
|
||
|
||
```swift
|
||
// APM.dylib
|
||
public class APMManager {
|
||
public init () {
|
||
|
||
}
|
||
}
|
||
|
||
// 另一个模块(动态库/静态库/主工程)
|
||
var manager = APMManager()
|
||
```
|
||
|
||
|
||
|
||
## 枚举类型
|
||
|
||
不能给 enum 的 case 单独设置访问级别,每个 case 自动对齐 enum 的访问级别
|
||
|
||
- public 的 enum,各个 case 也是 public
|
||
|
||
|
||
|
||
## 协议
|
||
|
||
协议中定义的要求自动接收协议的访问级别,不能单独设置访问级别
|
||
|
||
- public 定义的协议,各个属性、方法也是 public 级别
|
||
|
||
协议实现的访问级别 >= 类型的访问级别(协议的访问级别)
|
||
|
||
```swift
|
||
// 编译通过
|
||
public protocol Runnable {
|
||
func run()
|
||
}
|
||
internal class Person : Runnable {
|
||
internal func run() { }
|
||
}
|
||
// 编译失败
|
||
public protocol Runnable {
|
||
func run()
|
||
}
|
||
public class Person : Runnable {
|
||
internal func run() { } // Method 'run()' must be declared public because it matches a requirement in public protocol 'Runnable'
|
||
}
|
||
```
|
||
|
||
|
||
|
||
|
||
|