In the area of access control, Swift provides five different access levels.

One, access control keywords

The following are listed from highest to lowest (entities: content modified by access level; Module: this project or other third party library) :

  • open: allows access in the module that defines the entity, in other modules, allowing other modules to inherit, overwrite (openCan only be used with classes or class members.
  • public: Allows access in the module that defines the entity or in other modules. Does not allow other modules to inherit or overwrite the entity
  • internal: Allows access only in the module that defines the entity, not in other modules
  • fileprivate: Allows access only in the source file that defines the entity
  • private: Allows access only in closed declarations that define entities

Most entities default to the internal level.

Two, the use of guidelines

An entity may not be defined by an entity with a lower level of access.

  • Variable/constant typepVariable/constant
  • Parameter type/return value typepfunction
  • The parent classpA subclass
  • The parent agreementpThe child agreement
  • The original typep typealias
  • Original value type/associated value typepEnumerated type
  • Other types used to define type ApType A

Example code 1 (error) :

fileprivate class Person {}internal var person: Person
Copy the code

This error occurs because the internal modifier person allows the module that defines the entity to access (Targets all Swift source files), while Fileprivate restricts the use of the person type to the current source file.

Example code 2 (correct) :

public class Person {}internal var person: Person
Copy the code

Anyway, in the above criteria,pThe access on the left must be greater than or equal to the access on the right.

Three, various types of access levels

3.1. Tuple types

The tuple type has the lowest level of access of all member types.

Sample code:

internal struct Dog {}fileprivate class Person {}fileprivate var data1: (Dog.Person)
private var data2: (Dog.Person)
Copy the code

Data1 and data2 are variables. (Dog, Person) is a tuple type. Person has a lower access level than Dog, so the tuple type access level is Fileprivate.

3.2. Generic types

The access level of a generic type is the lowest of the access level of the type and the access level of all generic type parameters.

Sample code:

internal class Car {}fileprivate class Dog {}public class Person<T1.T2> {}fileprivate var p = Person<Car.Dog> ()Copy the code

The access level of the generic type Person

is the lowest of Person’s and Car’s and Dog’s access levels, namely fileprivate.
,>

3.3. Member/nested types

The access level of a type affects the default access level for members (properties, methods, initializers, subscripts) and nested types.

3.3.1. Typeprivateorfileprivate

In general, if the type is private or Fileprivate, the member/nested type is also private or Fileprivate by default.

Sample code:

private class Person {
    var age = 0
    func run(a){}enum Seaon { case spring, summer }
}
Copy the code

The access level for the variable age, function run, and nested type Season is private.

3.3.2 rainfall distribution on 10-12. Typeinternalorpublic

In general, if the type is internal or public, the member/nested type defaults to internal.

Example code 1:

public class Person {
    var age = 0
    func run(a){}enum Seaon { case spring, summer }
}
Copy the code

The access level for the variable age, function run, and nested type Season is internal.

Example code 2:

public class PublicClass { // public
    public var p1 = 0 // internal
    var p2 = 0 // internal
    fileprivate func f1(a){}// fileprivate
    private func f2(a){}// private
}

class InternalClass { // internal
    var p = 9 // internal
    fileprivate func f1(a){}// fileprivate
    private func f2(a){}// private
}

fileprivate class FileprivateClass { // fileprivate
    func f1(a){}// fileprivate
    private func f2(a){}// private
}

private class PrivateClass { // private
    func f(a){}// private
}
Copy the code

3.4. Rewriting of members

The access level of the member overridden by a subclass must be ≥ the access level of the subclass or ≥ the access level of the overridden member of the parent class.

3.4.1. Example code 1

A member of a parent class cannot be overridden by a child class defined outside the member scope.

Correct examples:

public class Person {
    private var age: Int = 0
    public class Student: Person {
        override var age: Int {
            set{}get { 10}}}}Copy the code

3.4.2. Example Code two

private class Person {}fileprivate class Student : Person {}Copy the code

Does the sample code above compile? It really depends.

  1. If you put the sample code in the outermost layer (the main file is an example), it compiles fine.

  2. If we put the sample code in the internal class:

Error: Parent class level needs to be greater than subclass level.

Class access restricted to the private Person class. The subclass has a higher access level than the parent class. If the code is placed in the outermost layer, whether private or fileprivate, the scope of the restriction is the entire source file, so no errors are reported.

3.4.3. Example Code 3

private struct Dog {
    var age: Int = 0
    func run(a){}}fileprivate struct Person {
    var dog: Dog = Dog(a)mutating func walk(a) {
        dog.run()
        dog.age = 1}}Copy the code

And the example code is consistent, put in the class error, put in the source file root layer to compile normally.

But what if the Dog member variable and inner function in the code above had private access restrictions?

Error:

Analysis: Because Dog’s internal member variables and functions are controlled by private, they are only used within Dog and cannot be accessed externally.

Private, defined directly in global scope, is equivalent to Fileprivate.

3.4.4. Example Code 4

class Test {
    private struct Dog {
        var age: Int = 0
        func run(a){}}private struct Person {
        var dog: Dog = Dog(a)mutating func walk(a) {
            dog.run()
            dog.age = 1}}}Copy the code

Dog is private, but you can still use Dog and its internal attributes in Person. Attribute access rights in Dog are private by default, but when access rights are not explicitly declared, internal attributes have the same scope and type. So you can use Dog’s internal properties in Person.

3.5. The getter and setter

Getters and setters automatically receive the access level of their environment by default.

Setters can be given a separate access level lower than getters to restrict write permissions (getters cannot be given separate access).

Sample code:

fileprivate(set) public var num = 10
class Person {
    private(set) var age = 0
    fileprivate(set) public var weight: Int {
        set{}get { 10}}internal(set) public subscript(index: Int) -> Int {
        set{}get { index }
    }
}
Copy the code

3.6. Initializer

  1. If apublicclassThe compile-generated default no-argument initializer that you want to invoke in another module must be explicitly providedpublicThe no-parameter initializer for. becausepublicclassThe default initializer forinternalLevel.

Example code 1:

public class Person {}var p = Person(a)Copy the code

Given that the above sample code is in a dynamic library, there is no way to call the no-argument initializer for Person in the current project, because everything inside a class that public decorates is internal by default.

If you want to use a no-parameter initializer for Person, you need to explicitly provide the no-parameter initializer and use a modifier above the public level.

Example code two (can be used by outsiders with a no-parameter initializer) :

public class Person {
    public init(a){}}var p = Person(a)Copy the code
  1. requiredThe initializerpIts default access level.

Sample code:

public class Person {
    fileprivate required init(a){}}Copy the code

Fileprivate must be replaced with a higher level of access.

  1. If the structure hasprivate/fileprivateStore instance properties, so do their member initializersprivate/fileprivateOtherwise, the default isinternal.

Example code 1:

struct Point {
    fileprivate var x = 0
    var y = 0
}
var p = Point(x: 10, y: 20)
Copy the code

The access level for Point(x: 10, y: 20) is Fileprivate.

Example code 2:

struct Point {
    private var x = 0
    var y = 0
}
var p = Point(y: 20)
Copy the code

As long as one of the storage properties is private, all member initializers cannot be used (and the compiler no longer generates them automatically), only no-parameter initializers can be used.

3.7. Cases of enumerated types

An access level cannot be set separately for each case of an enum.

Each case automatically receives enum access level.

Public enums define cases that are also public (unlike structures/classes).

3.8. The agreement

Protocol definition requires (code) automatically receive protocol access level, cannot be set separately (similar to enumeration).

The access level of the protocol implementation must be greater than or equal to the access level of the type or protocol.

Example code 1:

internal protocol Runnable {
    func run(a)
}

fileprivate class Person : Runnable {
    public func run(a){}}Copy the code

Protocol implementation func run() {} access level ≥ (take the lowest access level of both type Person and protocol Runnable).

Example code 2:

public protocol Runnable {
    func run(a)
}

public class Person : Runnable {
    func run(a){}}Copy the code

Because classes that use public, their internal members and functions are internal, while protocols and classes are public, the lowest level of functions in a class should use public.

public class Person : Runnable {
    public func run(a){}}Copy the code

3.9 extensions

  1. If the extension’s access level is explicitly set, members added to the extension automatically receive the extension’s access level.

  2. If the access level of the extension is not explicitly set, the default access level for members added by the extension is the same as for members defined directly in the type.

  3. Access levels can be set separately for members added to the extension.

  4. Extensions used for protocol compliance cannot be explicitly set to the access level of the extension.

  1. Extensions in the same file can be written as type declarations in multiple parts.
    • Declare a private member in the original declaration that can be accessed in an extension of the same file
    • Declare a private member in an extension that can be accessed in other extensions of the same file, in the original declaration

Sample code:

public class Person {
    private func run0(a){}private func eat0(a) {
        run1()
    }
}

extension Person {
    private func run1(a){}private func eat1(a) {
        run0()
    }
}

extension Person {
    private func eat2(a) {
        run1()
    }
}
Copy the code

Whenever a class is extended in the same file, it simply splits the class into multiple declarations.

3.10. Assign the method to var/let

Methods can also be assigned to a let or var, like functions.

Sample code:

struct Person {
    var age: Int
    func run(_ v: Int) {
        print("func run", age, v)
    }
    static func run(_ v: Int) {
        print("static func run", v)
    }
}

let fn1 = Person.run
fn1(10) // Static func run 10

let fn2: (Int) - > ()= Person.run
fn2(20) // Static func run 20

// The instance is passed to the variable
let fn3: (Person) - > ((Int) - > ())= Person.run
fn3(Person(age: 18(a))30) Func run 18 30
Copy the code

For more articles in this series, please follow our wechat official account [1024 Planet].