アクセス修飾子
クラス、ストラクチャ、列挙型、プロパティ、メソッド、イニシャライザ、subscript、プロトコル、グローバル変数・定数・関数は、次のようなアクセス修飾子を付けることで、型やプロパティがアクセスできる範囲を定めることができます。
public:外部モジュールのコードからもアクセス可能であることを示す。
internal:定義されたモジュール内部のコードからしかアクセスできないことを示す。
private:定義されたファイル内部のコードからしかアクセスできないことを示す。
ここでいう「モジュール」とは、XcodeがSwiftソースコードのビルドターゲットごとに生成するフレームワークやアプリケーションのことです。
通常、internalがデフォルトのアクセス修飾子です。変数やプロパティにアクセス修飾子の指定がない場合、internalアクセス修飾子が付けられたものとして扱われます。
型と内部のアクセス範囲
クラス、ストラクチャ、列挙型にアクセス修飾子を付けると、その型は、先ほど示した範囲からアクセス可能になります。
それぞれの型の内部に定義されるプロパティ、メソッド、イニシャライザ、subscriptには、定義された型のアクセス範囲に基づき、次の例のようにアクセス範囲が決められます。
public struct PublicStruct {
public let publicConstant = 1 // モジュール外からアクセス可能
var internalVariable = 2 // モジュール内からアクセス可能
private var privateVariable = 3 // ファイル内からアクセス可能
}
struct InternalStruct {
let internalConstant = 4 // モジュール内からアクセス可能
private var privateVariable = 5 // ファイル内からアクセス可能
}
private struct PrivateStruct {
let constant = 6 // ファイル内からアクセス可能
private let privateConstant = 7 // ファイル内からアクセス可能
}
なお、通常はinternalがデフォルトのアクセス修飾子として設定されますが、privateな型では、privateがデフォルトのアクセス修飾子となります。
タプル、関数のアクセス範囲
タプルのアクセス範囲は、タプルに含まれる型のアクセス範囲のうち、最も狭いものが適用されます。 関数のアクセス範囲についても同じように、引数の型と返り値の型のアクセス範囲のうち、最も狭いものが適用されます。 例を見てみましょう。 PublicStruct、InternalStruct、PrivateStructの3つの型は、前項で宣言したものです。
private var privateTuple : (PublicStruct, InternalStruct, PrivateStruct)?
private func privateFunc (PrivateStruct) -> PublicStruct {
return PublicStruct()
}
タプルprivateTupleに含まれる型、関数privateFuncの引数および返り値の型のいずれも、アクセス範囲が最も狭いものはPrivateStructです。そのため、両者はPrivateStructに合わせてprivateとして宣言される必要があります。
列挙型のメンバーのアクセス範囲
列挙型のメンバーのアクセス範囲は、プロパティ、メソッド、イニシャライザ、subscriptとは異なり、列挙型のアクセス範囲と同じになります。
public enum Result {
case Success
case Failure
}
この例ではSuccess、Failureのいずれもモジュール外からアクセス可能です。
サブクラスでのアクセス範囲
クラスの継承においては、次のようなアクセス範囲変更のルールがあります。
- サブクラスのアクセス範囲は継承元のクラスよりも狭いか同等。
- サブクラスのオーバーライドされたメソッド、イニシャライザは継承元よりも広いアクセス範囲にできる。
例で確認しましょう。
public class PublicClass {
private func action() {
}
}
class InternalClass : PublicClass {
internal override func action() {
}
}
この例からは、オーバーライドされたメソッドがより広いアクセス権限に変更できることがわかります。
setterへの修飾子
プロパティとsubscriptへのsetterに対しては、アクセス修飾子(set)を通常のアクセス修飾子の後に置く宣言方法で、getterよりも狭いアクセス範囲を指定できます。例を見てみましょう。
public class Bank {
public private(set) var amountOfMoney = 10000
public func pull(amount: Int) {
amountOfMoney -= amount
}
}
このような宣言方法をとることにより、他のファイルにあるコード上で、BankのamountOfManeyに代入する操作を禁止することができます。
var bank = Bank() var amount = bank.amountOfMoney bank.pull(1000) bank.amountOfMoney = 1 // エラー
この場合、amountOfMoneyプロパティがgetterについてはpublic、setterについてはprivateであるために、他のファイル上ではプロパティの中身を取得することはできますが、変更操作は直接行えないことがわかります。
特殊なイニシャライザのアクセス範囲
通常のイニシャライザは定義された型と同じかそれよりも狭いアクセス範囲を指定しますが、requiredキーワードを付けられたイニシャライザは、定義された型と同じアクセス範囲を指定しなければなりません。requiredキーワードを付けられたイニシャライザは、サブクラスでもrequiredを付けて宣言し、スーパークラスでの自身のイニシャライザを呼ぶ必要があることがその理由です。
public class PublicClass {
required public init() { // public以外の範囲を指定するとエラー
}
}
ストラクチャおよび基底クラスのすべての保持プロパティにデフォルト値が設定されていて、かつイニシャライザを定義していないときに提供されるデフォルトイニシャライザは、型と同じアクセス範囲を持ちます。
public class PublicClass {
var value = 1
} // publicのアクセス範囲でデフォルトイニシャライザを用いてPublicClass()で初期化できる
ストラクチャの場合、保持プロパティのデフォルト値が1つも設定されておらず、イニシャライザを定義していないときには、メンバー付きのイニシャライザが提供されます。このメンバー付きイニシャライザに関しては、保持プロパティに1つでもprivateなものがある場合、アクセス範囲はprivateとなり、そうでない場合はinternalとなります。
publicなメンバー付きイニシャライザは、プログラマが自分の手で実装する必要があることに注意してください。
