迅速なアクセス制御


アクセス制御は、他のソースファイルまたはモジュール内のコードのコードへのアクセスレベルを制限できます。

個々の型 (クラス、構造体、列挙)、またはこれらの型のプロパティ、関数、初期化メソッド、基本型、添字インデックスなどに対してアクセス レベルを明示的に設定できます。

プロトコルは、プロトコル内のグローバル定数、変数、関数などの特定の範囲に制限することもできます。

アクセス制御はモジュールとソースファイルに基づいています。

モジュールとは、独立したユニットとして構築および公開されるフレームワークまたはアプリケーションを指します。 Swift では、モジュールは import キーワードを使用して別のモジュールをインポートできます。

ソース ファイルは単一のソース コード ファイルであり、通常はモジュールに属します。ソース ファイルには複数のクラスと関数の定義を含めることができます。

Swift は、コード内のエンティティに対してパブリック、内部、プライベートの 3 つの異なるアクセス レベルを提供します。

アクセスレベル定義
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() {}

特別な指示がない限り、エンティティはデフォルトのアクセス レベル external を使用します。


関数型のアクセス権

関数のアクセスレベルは、関数のパラメータ型と戻り値の型のアクセスレベルに基づいて導出する必要があります。

次の例では、someFunction という名前のグローバル関数を定義していますが、そのアクセス レベルは明示的に宣言していません。

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

関数内のクラスの 1 つである SomeInternalClass のアクセス レベルは内部であり、もう 1 つのクラスである SomePrivateClass のアクセス レベルはプライベートです。したがって、タプルのアクセス レベルの原則に従って、このタプルのアクセス レベルはプライベートです。

この関数の戻り値の型のアクセス レベルはプライベートであるため、関数を明示的に宣言するには private 修飾子を使用する必要があります:
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
    // 函数实现
}

関数を public または external として宣言したり、デフォルトのアクセス レベル external を使用したりするのは誤りです。


列挙型のアクセス権

列挙型のメンバーのアクセス レベルは列挙型から継承されます。列挙型のメンバーに対して異なるアクセス レベルを個別に宣言することはできません。

インスタンス

たとえば、次の例では、列挙 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

子クラスのアクセス権

サブクラスのアクセス レベルは、親クラスのアクセス レベルを超えてはなりません。たとえば、親クラスのアクセス レベルが内部の場合、サブクラスのアクセス レベルをパブリックとして宣言することはできません。

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

ゲッターおよびセッターのアクセス権

定数、変数、プロパティ、およびインデックス付きのゲッターとセッターのアクセス レベルは、それらが属するメンバーのアクセス レベルから継承されます。

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 は、構造体とクラスに対してデフォルトのパラメーターなしの初期化メソッドを提供します。これは、すべてのプロパティに対する代入操作を提供するために使用されますが、特定の値は与えられません。

デフォルトの初期化メソッドのアクセスレベルは、それが属するタイプのアクセスレベルと同じです。

インスタンス

アクセス許可を宣言するには、各サブクラスの 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", "泛型", "类型参数", "类型参数名"]

型エイリアス

定義した型エイリアスは、アクセス制御を容易にするために別の型として扱われます。タイプ エイリアスのアクセス レベルは、元のタイプのアクセス レベルより高くすることはできません。

たとえば、プライベート レベルの型エイリアスはパブリック、内部、またはプライベート タイプに設定できますが、パブリック レベルの型エイリアスはパブリック レベルの型にのみ設定でき、内部レベルやプライベート レベルには設定できません。タイプ。

注: このルールは、プロトコル準拠のためのエイリアス関連タイプにも適用されます。

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 语句"]