访问控制,swift3学习笔记

访问修饰符有:open、public、internal、fileprivate、private访问修饰符可以修饰面向对象的类型,以及变量常量下标元组函数属性等“实体”。

原创文章,欢迎转载。转载请注明:关东升的博客

访问控制可以限定其他源文件或模块中代码对你代码的访问级别。你可以明确地给单个类型(类、结构体、枚举)设置访问级别,也可以给这些类型的属性、函数、初始化方法、基本类型、下标索引等设置访问级别。协议也可以被限定在一定的范围内使用,包括协议里的全局常量、变量和函数。访问控制基于模块与源文件。模块指的是以独立单元构建和发布的 Framework 或 Application。在 Swift 中的一个模块可以使用 import 关键字引入另外一个模块。源文件是单个源码文件,它通常属于一个模块, 源文件可以包含多个类和函数 的定义。Swift 为代码中的实体提供了四种不同的访问级别:public、internal、fileprivate、private。访问级别定义public可以访问自己模块中源文件里的任何实体,别人也可以通过引入该模块来访问源文件里的所有实体。internal可以访问自己模块中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。fileprivate文件内私有,只能在当前源文件中使用。private只能在类中访问,离开了这个类或者结构体的作用域外面就无法访问。public 为最高级访问级别,private 为最低级访问级别。语法通过修饰符public、internal、fileprivate、private来声明实体的访问级别:实例public class SomePublicClass {}internal class SomeInternalClass {}fileprivate class SomeFilePrivateClass {}private class SomePrivateClass {} public var somePublicVariable = 0internal let someInternalConstant = 0fileprivate func someFilePrivateFunction() {}private func somePrivateFunction() {}除非有特殊的说明,否则实体都使用默认的访问级别 internal。未指定访问级别默认为 internalclass SomeInternalClass {}              // 访问级别为 internallet someInternalConstant = 0            // 访问级别为 internal函数类型访问权限函数的访问级别需要根据该函数的参数类型和返回类型的访问级别得出。下面的例子定义了一个名为someFunction全局函数,并且没有明确地申明其访问级别。func someFunction() -> (SomeInternalClass, SomePrivateClass) {    // 函数实现}函数中其中一个类 SomeInternalClass 的访问级别是 internal,另一个 SomePrivateClass 的访问级别是 private。所以根据元组访问级别的原则,该元组的访问级别是 private(元组的访问级别与元组中访问级别最低的类型一致)。因为该函数返回类型的访问级别是 private,所以你必须使用 private 修饰符,明确的声明该函数:private func someFunction() -> (SomeInternalClass, SomePrivateClass) {    // 函数实现}将该函数申明为 public 或 internal,或者使用默认的访问级别 internal 都是错误的,因为如果这样你就无法访问 private 级别的返回值。枚举类型访问权限枚举中成员的访问级别继承自该枚举,你不能为枚举中的成员单独申明不同的访问级别。实例比如下面的例子,枚举 Student 被明确的申明为 public 级别,那么它的成员 Name,Mark 的访问级别同样也是 public:实例public enum Student {    case Name(String)    case Mark(Int,Int,Int)} var studDetails = Student.Name("Swift")var studMarks = Student.Mark(98,97,95) switch studMarks {case .Name(let studName):    print("学生名: (studName).")case .Mark(let Mark1, let Mark2, let Mark3):    print("学生成绩: (Mark1),(Mark2),(Mark3)")}以上程序执行输出结果为:学生成绩: 98,97,95子类访问权限子类的访问级别不得高于父类的访问级别。比如说,父类的访问级别是internal,子类的访问级别就不能申明为public。实例public class SuperClass {    fileprivate func show() {        print("超类")    }} // 访问级别不能低于超类 internal > publicinternal class SubClass: SuperClass  {    override internal func show() {        print("子类")    }} let sup = SuperClass()sup.show() let sub = SubClass()sub.show()以上程序执行输出结果为:超类子类常量、变量、属性、下标访问权限常量、变量、属性不能拥有比它们的类型更高的访问级别。比如说,你定义一个public级别的属性,但是它的类型是private级别的,这是编译器所不允许的。同样,下标也不能拥有比索引类型或返回类型更高的访问级别。如果常量、变量、属性、下标索引的定义类型是private级别的,那么它们必须要明确的申明访问级别为private:private var privateInstance = SomePrivateClass()Getter 和 Setter访问权限常量、变量、属性、下标索引的Getters和Setters的访问级别继承自它们所属成员的访问级别。Setter的访问级别可以低于对应的Getter的访问级别,这样就可以控制变量、属性或下标索引的读写权限。实例class Samplepgm {    fileprivate var counter: Int = 0{        willSet(newTotal){            print("计数器: (newTotal)")        }        didSet{            if counter > oldValue {                print("新增加数量 (counter - oldValue)")            }        }    }} let NewCounter = Samplepgm()NewCounter.counter = 100NewCounter.counter = 800counter 的访问级别为 fileprivate,在文件内可以访问。以上程序执行输出结果为:计数器: 100新增加数量 100计数器: 800新增加数量 700构造器和默认构造器访问权限初始化我们可以给自定义的初始化方法申明访问级别,但是要不高于它所属类的访问级别。但必要构造器例外,它的访问级别必须和所属类的访问级别相同。如同函数或方法参数,初始化方法参数的访问级别也不能低于初始化方法的访问级别。默认初始化方法Swift为结构体、类都提供了一个默认的无参初始化方法,用于给它们的所有属性提供赋值操作,但不会给出具体值。默认初始化方法的访问级别与所属类型的访问级别相同。实例在每个子类的 init() 方法前使用 required 关键字声明访问权限。实例class classA {    required init() {        var a = 10        print(a)    }} class classB: classA {    required init() {        var b = 30        print(b)    }} let res = classA()let show = classB()以上程序执行输出结果为:103010协议访问权限如果想为一个协议明确的申明访问级别,那么需要注意一点,就是你要确保该协议只在你申明的访问级别作用域中使用。如果你定义了一个public访问级别的协议,那么实现该协议提供的必要函数也会是public的访问级别。这一点不同于其他类型,比如,public访问级别的其他类型,他们成员的访问级别为internal。实例public protocol TcpProtocol {    init(no1: Int)} public class MainClass {    var no1: Int // local storage    init(no1: Int) {        self.no1 = no1 // initialization    }} class SubClass: MainClass, TcpProtocol {    var no2: Int    init(no1: Int, no2 : Int) {        self.no2 = no2        super.init(no1:no1)    }        // Requires only one parameter for convenient method    required override convenience init(no1: Int)  {        self.init(no1:no1, no2:0)    }} let res = MainClass(no1: 20)let show = SubClass(no1: 30, no2: 50) print("res is: (res.no1)")print("res is: (show.no1)")print("res is: (show.no2)")以上程序执行输出结果为:res is: 20res is: 30res is: 50扩展访问权限你可以在条件允许的情况下对类、结构体、枚举进行扩展。扩展成员应该具有和原始类成员一致的访问级别。比如你扩展了一个公共类型,那么你新加的成员应该具有和原始成员一样的默认的internal访问级别。或者,你可以明确申明扩展的访问级别(比如使用private extension)给该扩展内所有成员申明一个新的默认访问级别。这个新的默认访问级别仍然可以被单独成员所申明的访问级别所覆盖。泛型访问权限泛型类型或泛型函数的访问级别取泛型类型、函数本身、泛型类型参数三者中的最低访问级别。实例public struct TOS{    var items = [T]()    private mutating func push(item: T) {        items.append(item)    }        mutating func pop() -> T {        return items.removeLast()    }} var tos = TOS()tos.push("Swift")print(tos.items) tos.push("泛型")print(tos.items) tos.push("类型参数")print(tos.items) tos.push("类型参数名")print(tos.items)let deletetos = tos.pop()以上程序执行输出结果为:["Swift"]["Swift", "泛型"]["Swift", "泛型", "类型参数"]["Swift", "泛型", "类型参数", "类型参数名"]类型别名任何你定义的类型别名都会被当作不同的类型,以便于进行访问控制。一个类型别名的访问级别不可高于原类型的访问级别。比如说,一个private级别的类型别名可以设定给一个public、internal、private的类型,但是一个public级别的类型别名只能设定给一个public级别的类型,不能设定给internal或private 级别的类型。注意:这条规则也适用于为满足协议一致性而给相关类型命名别名的情况。实例public protocol Container {    typealias ItemType    mutating func append(item: ItemType)    var count: Int { get }    subscript(i: Int) -> ItemType { get }} struct Stack: Container {    // original Stackimplementation    var items = [T]()    mutating func push(item: T) {        items.append(item)    }        mutating func pop() -> T {        return items.removeLast()    }        // conformance to the Container protocol    mutating func append(item: T) {        self.push(item)    }        var count: Int {        return items.count    }        subscript(i: Int) -> T {        return items[i]    }} func allItemsMatch<    C1: Container, C2: Container    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>    (someContainer: C1, anotherContainer: C2) -> Bool {        // check that both containers contain the same number of items        if someContainer.count != anotherContainer.count {            return false        }                // check each pair of items to see if they are equivalent        for i in 0..()

访问控制
(private,fileprivate,internal,public,open)

模块:一个应用程序包(Application可以执行,包含很多Swift文件以及其他文件)或者 一个框架(不可执行文件,Swift文件以及其他文件的集合) import引用源文件:.swift文件,编译之后被包含在应用程序包或者框架中

访问级别:

tos.push("Swift")

访问权限从高到低:open > public > interal > fileprivate > private

1、open任何open实体,无论在自己模块,还是其他模块都可以被访问,open有个使用说明:only classes and overridable class members can be declared 'open'--即open只能适用于类class2、public约等于open,在同一模块中open等于public,在不同模块时,public所声明的类不能被继承,public所声明的属性和方法不能被重写3、internal默认访问权限。只能在自己模块中被访问4、fileprivate只能在当前文件中被访问5、private只能在类型内部被访问

Swift提供了3种不同访问级别,对应的访问修饰符为:public、internal和private。这些访问修饰符可以修饰类、结构体、枚举等面向对象的类型,还可以修饰变量、常量、下标、元组、函数、属性等内容。

print(tos.items)

访问级别知道原则:
Access levels in Swift follow an overall guiding principle: No entity can be defined in terms of another entity that has a lower (more restrictive) access level.

统一性原则1、如果一个类型(包括类、结构体、枚举),定义为internal或者private,那么类型声明的变量或者常量不能使用public访问级别。

 public。可以访问自己模块中的任何public实体。如果使用import语句引入其他模块,我们可以访问其他模块中的public实体。

tos.push("泛型")

For example:

 private class Employee{ var no: Int = 0 var name: String = "" var job: String? var salary: Double = 0 var dept: Department?} internal struct Department{ var no: Int = 0 var name: String = ""} public let emp = Employee() // fileprivateprivate是可以的 public var dept = Department() // 编译报错:Playground execution failed: error: MyPlayground.playground:12:12: error: constant cannot be declared public because its type 'Employee' uses a private type public let emp = Employee() ^error: MyPlayground.playground:13:12: error: variable cannot be declared public because its type 'Department' uses an internal typepublic var dept = Department() ^

 internal。只能访问自己模块的任何internal实体,不能访问其他模块中的internal实体。internal可以省略,换句话说,默认访问限定是internal。

print(tos.items)

A public variable cannot be defined as having an internal, file-private, or private type, because the type might not be available everywhere that the public variable is used.

A function cannot have a higher access level than its parameter types and return type, because the function could be used in situations where its constituent types are not available to the surrounding code.

2、函数的访问权限级别不能高于它的参数和返回值类型的访问级别

 private。只能在当前源文件中使用的实体,称为私有实体。使用private修饰,可以用作隐藏某些功能的实现细节。

tos.push("Where 语句")

The specific implications of this guiding principle for different aspects of the language are covered in detail below.

 class Employee{ var no: Int = 0 var name: String = "" var job: String? var salary: Double = 0 var dept: Department? }struct Department{ var no: Int = 0 var name: String = "" }public func getEmpDept(emp: Employee)->Department?{ return emp.dept}// 编译失败:Playground execution failed: error: MyPlayground.playground:11:14: error: function cannot be declared public because its parameter uses an internal typepublic func getEmpDept(emp: Employee)->Department?{ ^ ~~~~~~~~ 会有函数可以被任何人访问,而他的参数和返回类型不可以访问的矛盾情况

使用访问修饰符的示例代码如下:

print(tos.items)

1. private

  • private修饰类,表示该类只能在当前Swift源文件中访问,且该类不能被继承。
![](https://upload-images.jianshu.io/upload_images/2267273-4284839f9f8043e5.png)

private修饰类,该类不能被继承
  • private修饰的属性或者方法,表示该属性或方法只能在当前类里访问,且不能override。
![](https://upload-images.jianshu.io/upload_images/2267273-f277c505c105925d.png)

private修饰的方法不能override



![](https://upload-images.jianshu.io/upload_images/2267273-1fc2c90cbb827321.png)

private修饰的方法不能在其他类中访问



![](https://upload-images.jianshu.io/upload_images/2267273-b4ee04c2d8fea2e4.png)

private修饰的属性不能在其他类中访问

设计原则1、如果本应用程序访问,默认的访问级别就可以。2、如果是框架的开发,让别人使用的就public,不让别人看到的就设定为internal private

public class PublicClass {}

var eos = ["Swift", "泛型", "Where 语句"]

2. fileprivate

  • fileprivate修饰类,表示该类只能在当前Swift源文件中访问,且该类不能被继承。
![](https://upload-images.jianshu.io/upload_images/2267273-24012551036b5769.png)

fileprivate修饰类,该类不能被继承
  • fileprivate修饰的属性或方法,被修饰的属性或方法可以在当前的Swift源文件里访问,但不能在其他源文件中访问。
![](https://upload-images.jianshu.io/upload_images/2267273-afc69d4ffc362931.png)

fileprivate修饰的属性或方法可以在当前的Swift源文件里访问



![](https://upload-images.jianshu.io/upload_images/2267273-da5f789907316bd3.png)

fileprivate修饰的属性或方法不能在其他源文件中访问

元组类型的访问级别遵循元组中字段最低级的访问级别

internal class InternalClass {}

print(eos)

3. internal(默认访问级别,internal修饰符可写可不写)

  • internal修饰的属性或方法在源代码所在的整个模块都可以访问。
  • 如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。
  • 如果是App代码,也是在整个App代码,也是在整个App内部可以访问。
![](https://upload-images.jianshu.io/upload_images/2267273-acb305c8a41951a0.png)

internal修饰的属性或方法在源代码所在的整个模块都可以访问



![](https://upload-images.jianshu.io/upload_images/2267273-cf5ddb8f4da9de87.png)

internal修饰的属性或方法在其他Swift源代码可以访问

枚举类型的访问级别枚举类型的访问级别继承自该枚举,因此我们不能为枚举中的成员指定访问级别。

private class PrivateClass {}

以上程序执行输出结果为:

4. public

  • piblic修饰类,可以被任何人访问,但只能在本模块(sdk)中被继承。
  • public修饰属性和方法,可以被任何人访问,在module内可以被override和继承,但其他module中不可以被override和继承。

public var intPublicVariable = 0

["Swift"]

5. open

可以被任何人使用,不限制module,包括override和继承。

let intInternalConstant = 0

["Swift", "泛型"]

6. 部分说明

private func intPrivateFunction() {}

["Swift", "泛型", "Where 语句"]

6-1 访问控制语法(Access Control Syntax)
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePrivateFunction() {}

//默认为internal
class SomeInternalClass {}              // implicitly internal
let someInternalConstant = 0            // implicitly internal

使用最佳访问级别:

["Swift", "泛型", "Where 语句"]

6-2 自定义类型(Custom Types)

类的访问控制级别会影响该类成员的默认访问级别。

  • 如果将类的访问级别定义为private(私有)或fileprivate(文件私有),其成员的默认访问级别也将为private(私有)或fileprivate(文件私有)。
  • 如果将类的访问级别定义为internal或public(或者使用内部的默认访问级别,但未明确指定访问级别),那么类型成员的默认访问级别将是internal。
  • 一个访问控制级别是public的类,它的成员默认的访问控制级别是internal。如果你想要一个类型成员是public的,你必须明确标记它。
public class SomePublicClass {                  // explicitly public class
    public var somePublicProperty = 0            // explicitly public class member
    var someInternalProperty = 0                 // implicitly internal class member
    fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}

class SomeInternalClass {                       // implicitly internal class
    var someInternalProperty = 0                 // implicitly internal class member
    fileprivate func someFilePrivateMethod() {}  // explicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}

fileprivate class SomeFilePrivateClass {        // explicitly file-private class
    func someFilePrivateMethod() {}              // implicitly file-private class member
    private func somePrivateMethod() {}          // explicitly private class member
}

private class SomePrivateClass {                // explicitly private class
    func somePrivateMethod() {}                  // implicitly private class member
}

由于中Swift中访问限定符能够修饰的实体很多,使用起来比较繁琐,下面我们给出一些最佳实践。

6-3 元组类型(Tuple Types)
  • 元组类型的访问级别是该元组中使用的所有类型的最严格的访问级别。例如,如果一个元祖中有两种不同类型,一个具有internal(内部访问)权限,另一个具有private(私有访问)权限,则该复合元组类型的访问级别将是private(私有的)。

元组类型没有类,结构,枚举和函数所做的独立定义。当使用元组类型时,元组类型的访问级别会自动推断,并且不能明确指定。

  1. 统一性原则
6-4 函数类型(Function Types)
  • 函数类型的访问级别为函数的参数类型和返回类型的最严格的访问级别。如果函数的计算访问级别与指定的访问级别不一致,必须修改指定的访问级别相一致。
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // function implementation goes here
}
//函数的返回类型是一个元组类型,由被定义为internal的类和被定义为private的类组成。因此,复合元组类型的总体访问级别是`private`(元组的组成类型的最小访问级别)。
//因为函数的返回类型是private(私有的),所以必须private使用函数声明的修饰符将函数的总体访问级别标记为private。
//someFunction()使用public或internal修饰符 ,或者使用内部的默认设置,定义的都是无效的,因为函数的公共或内部用户可能没有对函数返回类型中使用的私有类的适当访问。

 原则1:如果一个类型(类、结构体、枚举)定义为internal或private,那么类型声明的变量或常量不能使用public访问级别。因为public的变量或常量可以被任何人访问,而internal或private的类型不可以。

6-5 子类
  • 子类的访问级别不能高于父类访问级别。例如:父类的访问级别是interal,子类的访问级别不能是public/open。
  • 可以覆盖 (override)任何类成员(方法、属性、初始化或下标)。
public class A {
    fileprivate func someMethod() {}
}
internal class B: A {
    override internal func someMethod() {}
}  
//使用internal修饰的class B继承自使用public修饰的class A,class B中可以修改class A中使用fileprivate修饰的someMethod()访问权限为internal。
//----------------------------------------
public class A {
    fileprivate func someMethod() {}
}
internal class B: A {
    override internal func someMethod() {
        super.someMethod()
    }
}
//由于父类A和子类B在同一个源文件中,子类B在重写someMethod()时可以调用super.someMethod()。

 原则2:函数的访问级别不能高于它的参数和返回类型(类、结构体、枚举)的访问级别。假设函数声明为public级别,而参数或者返回类型声明为internal或private,就会出现函数可以被任何人访问,而它的参数和返回类型不可以访问的矛盾情况。

6-6 常量,变量,属性和下标
  • 常量,变量,属性和下标的访问权限不能高于定义该变量所引用的类型或者返回类型。
//privateInstance的返回值访问权限类型是private,所以定义privateInstance的访问权限类型不能高于private。
private var privateInstance = SomePrivateClass()
  1. 设计原则

7. final

链接
Swift中,final关键字可以在class、func和var前修饰。
类或者方法的功能确实已经完备了,或避免子类继承和修改造成危险,或为了让父类中某些代码一定会执行。
也就是说这个类或方法不希望被继承和重写。

  • 用final关键字来防止重写
  • final,最后的,最终的;决定性的;不可更改的
  • final 修饰类的话,表示这个类不可以被继承。
  • 如果修饰属性或者方法,表示相应的属性或者方法不能被重写。

使用final修饰的类或属性或方法无论是在同一个module中还是在其他module中都不能被继承或者修改(override)。

//MARK: - ViewController:
//这个类在ViewController:的范围内不能被继承,只能能被访问;
//在ViewController:的范围外不能被继承,只能能被访问
final class NonSubclassAnyParentClass{}

//出错,在ViewController:范围不能被继承
class NonSubclassAny: NonSubclassAnyParentClass {}

//MARK: - LoginViewController
//出错,在ViewController:范围外不能被继承
class NonSubclassAny: NonSubclassAnyParentClass {}

参考链接1
参考链接2
参考链接3

用来记录平时遇到的问题,不对之处还望指教。

如果我们编写的是应用程序,应用程序包中的所有Swift文件和其中定义的实体,都是供本应用使用的,而不是提供其他模块使用,那么我们就不用设置访问级别了,即使用默认的访问级别。

如果我们开发的是框架,框架编译的文件不能独立运行,因此它天生就是给别人使用的,这种情况下我们要详细设计其中的Swift文件和实体的访问级别,让别人使用的可以设定为public,不想让别人看到的可以设定为internal或private。

  1. 元组类型的访问级别

元组类型的访问级别遵循元组中字段最低级的访问级别,例如下面的代码:

private class Employee {

var no: Int = 0

var name: String = ""

var job: String?

var salary: Double = 0

var dept: Department?

}

struct Department {

var no: Int = 0

var name: String = ""

}

private let emp = Employee()

var dept = Department()

private var student1 = (dept, emp)  ①

  1. 枚举类型的访问级别

枚举中成员的访问级别继承自该枚举,因此我们不能为枚举中的成员指定访问级别。示例代码如下:

public enum WeekDays {

case Monday

case Tuesday

case Wednesday

case Thursday

case Friday

}

由于WeekDays枚举类型是public访问级别,因而它的成员也是public级别。

本文由星彩网app下载发布于计算机编程,转载请注明出处:访问控制,swift3学习笔记

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。