신속한 접근 제어


액세스 제어를 통해 다른 소스 파일이나 모듈에 있는 코드의 액세스 수준을 사용자 코드로 제한할 수 있습니다.

개별 유형(클래스, 구조체, 열거형) 또는 이러한 유형의 속성, 함수, 초기화 방법, 기본 유형, 아래 첨자 인덱스 등에 대한 액세스 수준을 명시적으로 설정할 수 있습니다.

프로토콜은 프로토콜의 전역 상수, 변수 및 함수를 포함하여 특정 범위로 제한될 수도 있습니다.

액세스 제어는 모듈과 소스 파일을 기반으로 합니다.

모듈은 독립적인 단위로 구축 및 게시되는 프레임워크 또는 애플리케이션을 의미합니다. Swift에서 모듈은 import 키워드를 사용하여 다른 모듈을 가져올 수 있습니다.

소스 파일은 일반적으로 모듈에 속하는 단일 소스 코드 파일입니다. 소스 파일에는 여러 클래스 및 함수의 정의가 포함될 수 있습니다.

Swift는 코드의 엔터티에 대해 공개, 내부 및 비공개의 세 가지 액세스 수준을 제공합니다.

액세스 수준Definition
Public은 자체 모듈에서 소스 파일의 모든 엔터티에 액세스할 수 있으며, 다른 사람도 이 모듈을 도입하여 소스 파일의 모든 엔터티에 액세스할 수 있습니다.
Internal: 자신의 모듈에 있는 소스 파일의 모든 엔터티에 액세스할 수 있지만 다른 사람은 이 모듈에 있는 소스 파일의 엔터티에 액세스할 수 없습니다.
Private현재 소스 파일에서만 사용할 수 있는 엔터티를 프라이빗 엔터티라고 합니다.

Public은 가장 높은 접근 수준이고, Private은 가장 낮은 접근 수준입니다.

구문

public, Internal, Private 수정자를 통해 엔터티의 액세스 수준을 선언합니다.

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}

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

특별한 지침이 없는 한 엔터티는 내부 기본 액세스 수준을 사용합니다.


함수 유형 접근 권한

함수의 접근 수준은 함수의 매개변수 유형과 반환 유형의 접근 수준에 따라 파생되어야 합니다.

다음 예제에서는 someFunction이라는 전역 함수를 정의하고 해당 액세스 수준을 명시적으로 선언하지 않습니다.

func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
}

함수에 포함된 클래스 중 하나인 SomeInternalClass의 액세스 수준은 내부이고 다른 클래스인 SomePrivateClass의 액세스 수준은 비공개입니다. 따라서 튜플 액세스 수준의 원칙에 따라 이 튜플의 액세스 수준은 비공개입니다.

이 함수의 반환 유형에 대한 액세스 수준은 비공개이므로 함수를 명시적으로 선언하려면 private 수식자를 사용해야 합니다.
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
}

함수를 공개 또는 내부로 선언하거나 기본 액세스 수준을 내부로 사용하는 것은 잘못되었습니다.


열거형 액세스 권한

열거형 멤버의 액세스 수준은 열거형 멤버에 대해 별도로 다른 액세스 수준을 선언할 수 없습니다.

Instance

예를 들어 다음 예에서 열거형 Student는 공개 수준으로 명시적으로 선언되고 해당 멤버 Name 및 Mark의 액세스 수준도 공개됩니다.

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)")
}

위 프로그램 실행의 출력 결과 is:

学生成绩: 98,97,95

child 클래스 액세스 권한

하위 클래스의 액세스 수준은 상위 클래스의 액세스 수준보다 높을 수 없습니다. 예를 들어 상위 클래스의 액세스 수준이 내부인 경우 하위 클래스의 액세스 수준을 공개로 선언할 수 없습니다.

public class SuperClass {
    private func show() {
        print("超类")
    }
}

// 访问级别不能低于超类 internal > public
internal class SubClass: SuperClass  {
    override internal func show() {
        print("子类")
    }
}

let sup = SuperClass()
sup.show()

let sub = SubClass()
sub.show()

위 프로그램의 실행 출력은 다음과 같습니다.

超类
子类

상수, 변수, 속성, 아래 첨자 액세스 권한

상수, 변수, 속성은 해당 유형보다 높은 액세스 수준을 가질 수 없습니다.

예를 들어 공개 수준 속성을 정의했지만 해당 유형이 비공개 수준이므로 컴파일러에서 허용되지 않습니다.

마찬가지로 첨자는 인덱스 유형이나 반환 유형보다 높은 액세스 수준을 가질 수 없습니다.

상수, 변수, 속성 및 첨자 인덱스의 정의 유형이 비공개 수준인 경우 액세스 수준이 비공개임을 명시적으로 선언해야 합니다.

private var privateInstance = SomePrivateClass()

Getter 및 Setter 액세스 권한

상수, 변수, 속성 및 색인화된 getter 및 setter의 액세스 수준은 이들이 속한 멤버의 액세스 수준에서 상속됩니다.

Setter의 액세스 수준은 해당 Getter의 액세스 수준보다 낮을 수 있으므로 변수, 속성 또는 첨자 인덱스에 대한 읽기 및 쓰기 권한을 제어할 수 있습니다.

class Samplepgm {
    private var counter: Int = 0{
        willSet(newTotal){
            print("计数器: \(newTotal)")
        }
        didSet{
            if counter > oldValue {
                print("新增加数量 \(counter - oldValue)")
            }
        }
    }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

위 프로그램의 실행 출력은 다음과 같습니다.

计数器: 100
新增加数量 100
计数器: 800
新增加数量 700

생성자 및 기본 생성자 액세스 권한

초기화

사용자 정의 초기화 방법에 대한 액세스 수준을 선언할 수 있지만 액세스 수준보다 높아서는 안 됩니다. 그것이 속한 클래스. 필수 생성자는 예외이며 액세스 수준은 자신이 속한 클래스의 액세스 수준과 동일해야 합니다.

함수나 메서드 매개변수와 마찬가지로 초기화 메서드 매개변수의 액세스 수준은 초기화 메서드의 액세스 수준보다 낮을 수 없습니다.

기본 초기화 방법

Swift는 모든 속성에 대한 할당 작업을 제공하는 데 사용되지만 특정 값을 제공하지 않는 구조 및 클래스에 대한 기본 매개변수 없는 초기화 방법을 제공합니다.

기본 초기화 방법의 접근 수준은 그것이 속한 타입의 접근 수준과 동일합니다.

Instances

각 하위 클래스의 init() 메서드 앞에 필수 키워드를 사용하여 액세스 권한을 선언합니다.


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()

위 프로그램 실행의 출력 결과는 다음과 같습니다.

10
30
10

프로토콜 액세스 권한

프로토콜에 대한 액세스 수준을 명시적으로 선언하려면 한 가지에 주의해야 합니다. 즉, 프로토콜이 레벨 범위에서 사용됨으로 선언한 것만 액세스하는지 확인해야 합니다.

공개 액세스 수준으로 프로토콜을 정의하면 프로토콜을 구현하기 위해 제공되는 필수 기능도 공개 액세스 수준을 갖게 됩니다. 이는 멤버가 내부 액세스 수준을 갖는 공개 액세스 수준의 다른 유형과 같은 다른 유형과 다릅니다.

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: 20
res is: 30
res is: 50

확장된 액세스 권한

조건이 허용되면 클래스, 구조 및 열거형을 확장할 수 있습니다. 확장 멤버는 원래 클래스 멤버와 동일한 액세스 수준을 가져야 합니다. 예를 들어 공용 유형을 확장하는 경우 추가하는 새 멤버는 원래 멤버와 동일한 기본 내부 액세스 수준을 가져야 합니다.


또는 확장의 액세스 수준을 명시적으로 선언하여(예: 개인 확장 사용) 확장의 모든 구성원에 대한 새로운 기본 액세스 수준을 선언할 수 있습니다. 이 새로운 기본 액세스 수준은 개별 구성원이 선언한 액세스 수준으로 계속 재정의될 수 있습니다.


일반 접근 권한

제네릭 타입이나 제네릭 함수의 접근 수준은 제네릭 타입, 함수 자체, 제네릭 타입 매개변수 중 가장 낮은 접근 수준입니다.

public struct TOS<T> {
    var items = [T]()
    private mutating func push(item: T) {
        items.append(item)
    }
    
    mutating func pop() -> T {
        return items.removeLast()
    }
}

var tos = TOS<String>()
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", "泛型", "类型参数", "类型参数名"]

Type alias

정의한 모든 유형 별칭은 액세스 제어를 용이하게 하기 위해 다른 유형으로 처리됩니다. 유형 별칭의 액세스 수준은 원래 유형의 액세스 수준보다 높을 수 없습니다.

예를 들어 비공개 수준 유형 별칭은 공개, 내부 또는 비공개 유형으로 설정할 수 있지만 공개 수준 유형 별칭은 공개 수준 유형으로만 설정할 수 있으며 내부 또는 비공개 수준으로는 설정할 수 없습니다. 유형.

참고: 이 규칙은 프로토콜 준수를 위한 별칭 관련 유형에도 적용됩니다.

public protocol Container {
    typealias ItemType
    mutating func append(item: ItemType)
    var count: Int { get }
    subscript(i: Int) -> ItemType { get }
}

struct Stack<T>: Container {
    // original Stack<T> implementation
    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..<someContainer.count {
            if someContainer[i] != anotherContainer[i] {
                return false
            }
        }
        
        // all items match, so return true
        return true
}

var tos = Stack<String>()
tos.push("Swift")
print(tos.items)

tos.push("泛型")
print(tos.items)

tos.push("Where 语句")
print(tos.items)

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

위 프로그램 실행의 출력 결과는 다음과 같습니다.

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