一、访问控制
1. 在访问权限控制这块,Swift提供了5个不同的访问级别(以下是从高到低排列,实体指被访问级别修饰的内容)
1)open:允许在定义实体的模块,其他模块中访问(其他模块指的是库或者是其他的target),允许其他模块进行继承、重写(open只能用在类、类成员上)
2)public:允许在定义实体的模块,其他模块中访问,不允许其他模块进行继承和重写
3)internal:只允许在定义实体的模块中访问,不允许在其他模块中访问
4)fileprivate:只允许在定义实体的源文件中访问
5)private:只允许在定义实体的封闭声明中访问
2.绝大部分实体默认都是internal级别
二、访问级别的使用规则
1.一个实体不可以被更低访问级别的实体定义,比如:
1)变量/常量类型 >= 变量/常量
下面的例子就是错误的
//fileprivate class Person {
//
//}
//
//internal var person: Person
2)参数类型、返回值类型 >= 函数
func test(_ a: Int, _ b: Double) -> Double {
return 10.0
}
Int和Double类型是public修饰的,test函数是internal修饰的,所以正确
3)父类 >= 子类
public class Person {
}
class Student: Person {
}
4)原类型 >= typealias
class Person {
}
fileprivate typealias MJPerson = Person
fileprivate typealias MyInt = Int
fileprivate typealias MyString = String
public enum Score {
case point(MyInt)
case grade(MyString)
}
5)父协议>=子协议
6)原始值类型、关联值类型 >= 枚举类型
7)定义类型A时用到的其他类型 >= 类型A
三、元组类型
1.元组类型的访问级别是所有成员类型最低的那个
internal struct Dog {}
fileprivate class Person {}
// (Dog,Person)的访问级别是fileprivate
fileprivate var data1: (Dog, Person)
private var data2: (Dog, Person)
四、泛型类型
1.泛型类型的访问级别是类型的访问级别以及所有泛型类型参数的访问级别中最低的那个
internal class Car {}
fileprivate class Dog {}
public class Person<T1, T2> {}
// Person<Car, Dog>的访问级别是fileprivate
fileprivate var p = Person<Car, Dog>()
五、成员、嵌套类型
1.类型的访问级别会影响成员(属性、方法、初始化器、下标)、嵌套类型的默认访问级别
1)一般情况下,类型为private或fileprivate,那么成员、嵌套类型默认也是private或fileprivate
2)一般情况下,类型为internal或public,那么成员、嵌套类型默认为internal
public class PublicClass { // public
public var p1 = 0 // public
var p2 = 0 // internal
fileprivate func f1() { } // fileprivate
private func f2() { } // private
}
class InternalClass { // internal
var p = 0 // internal
fileprivate func f1() { } // fileprivate
private func f2() { } //private
}
fileprivate class FilePrivateClass { // fileprivate
func f1() { } // fileprivate
private func f2() { } // private
}
private class PrivateClass { // private
func f() { } // private
}
六、成员的重写
1.子类重写成员的访问级别必须 >= 子类的访问级别,或者子类被重写成员的访问级别
public class Person5 {
private var age: Int = 0
public class Student5 : Person5 {
override var age: Int {
set {}
get {10}
}
}
}
这段代码是编译没错的,age的作用域在Person5里面
2.父类的成员不能被成员作用域外定义的子类重写
public class Person2 {
private var age: Int = 0
}
public class Student2: Person2 {
override var age: Int {
set { }
get { 10 }
}
}
age只在Person2的作用域里面有效
七、下面代码能否编译通过
1.第一段代码
private class Person {}
fileprivate class Student: Person{}
可以编译通过,因为这个是在全局定义的,Person的访问级别也是这个文件
2.第二代代码
private struct Dog {
var age: Int = 0
func run() { }
}
fileprivate struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
可以编译通过,Dog是在全局定义的,是在整个文件里面有效,相当于fileprivate,那么他的成员age和run方法其实也相当于是fileprivate修饰
3.第三段代码
private struct Dog {
private var age: Int = 0
private func run() { }
}
fileprivate struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
相比于第二段代码,这个对age和run方法进行了显式声明为private,那么age和run的作用域只在Dog类里面,所以编译错误
4.第四段代码
class Test {
private struct Dog {
var age: Int = 0
func run() {}
}
private struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
}
可以编译通过,Dog的作用域是在Test这个函数里面,所以他的成员age和run方法的作用域也是在Test里面,可以进行访问在Person里面
5.第五段代码
class Test {
private struct Dog {
private var age: Int = 0
private func run() {}
}
private struct Person {
var dog: Dog = Dog()
mutating func walk() {
dog.run()
dog.age = 1
}
}
}
进行报错,age和fun只能在Dog里面进行访问
八、getter、setter
1、getter、setter默认自动接收它们所属环境的访问级别
2、可以给setter单独设置一个比getter更低的访问级别,用以限制写的权限
3、存储属性也有getter和setter,只是不能写{ set{ } ,get{ } }
class Person6 {
private(set) var age = 0
fileprivate(set) public var weight: Int {
set {}
get { 10 }
}
internal(set) public subscript(index: Int) -> Int {
set { }
get { index }
}
}
九、初始化器
1.如果一个public类想在另一个模块调用编译生成的默认无餐初始化器,必须显式提供public的无参初始化
1)因为public类的默认初始化器是internal级别
// abc.dylib
public class Person1 {
public init() {
}
}
// testSwift
var p = Person1()
2.required初始化器 >= 它的默认访问级别
3.如果结构体有private/fileprivate的存储实例属性,那么它的成员初始化器也是private/fileprivate
1)否则默认就是internal
2)成员初始化器指添加有参数的初始化器
struct Point {
fileprivate var x = 0
var y = 0
}
var p1 = Point(x: 10, y: 20)
上面的x是fileprivate修饰的存储属性,那么init(x,y)成员初始化器也是fileprivate
十、枚举类型的case
1.不能给enum的每个case单独设置访问级别
2.每个case自动接收enum的访问级别
1)public enum定义的case也是public
十一、协议
1.协议中定义的要求自动接收协议的访问级别,不能单独设置访问级别
1)public协议定义的要求也是public
Runnable协议是internal类型的,那么里面的不能进行单独的访问级别设置
2.协议实现的访问级别必须 >= 类型的访问级别,或者 >= 协议的访问级别
我们不可以在协议里面定义方法或者属性的访问级别,但是实现这个协议的具体实现我们可以去定义他的访问级别
internal protocol Runnable {
func run()
}
private class dogRun: Runnable {
fileprivate func run() {
}
}
上面中协议实现的访问级别是fileprivate,类型的访问级别是private,协议的访问级别是internal
3.协议和遵守这个协议的类之间的访问级别没有关系,协议的访问级别不一定大于遵守的类的级别
4.下面代码能编译通过么?
public protocol Runnable {
func run()
}
public class Person : Runnable {
func run() {}
}
编译报错,因为run()函数的访问级别是internal,而Person类和Runnable协议的访问级别是public
十二、拓展
1. 如果有显式设置拓展的访问级别,拓展添加的成员自动接收拓展分访问级别
2.如果没有显示设置拓展的访问级别,拓展添加的成员的默认访问级别,跟直接在类型中定义的成员一样
3.可以单独给拓展添加的成员设置访问级别
4.不能给用于遵守协议的拓展显式设置拓展的访问级别
5.在同一文件中的拓展,可以写成类似多个部分的类型声明
1)在原本的声明中声明一个私有成员,可以在同一文件的拓展中访问它
2)在拓展中声明一个私有成员,可以在同一文件的其他拓展中、原本声明中访问它
public class Person8 {
private func run0() { }
private func eat0() {
run1()
}
}
extension Person8 {
private func run1() { }
private func eat1() {
run0()
}
}
extension Person8 {
private func eat2() {
run1()
}
}
上面的代码没有错误,可以进行访问