Swiftのアクセスコントロールはファイル/モジュール単位だから気ィ付けや
公式ドキュメントはこちら The Swift Programming Language: Access Control
※ドキュメント以上のことは記載されていません。
SwiftにもXcode beta4からアクセスコントロールが可能になりました。
private
とかpublic
とかinternal
といった修飾子を付けることで、外部に公開する必要のないメソッドやクラスを隠蔽できます。
private
やpublic
を指定するのは、主に「クラス」と「インスタンス変数」だと思います。
「外部に公開するクラスはパブリックにしよう」とか、「この変数はクラス外から参照される必要がないので、プライベートにしよう」とかですね。
ただし、Swiftのアクセスコントロールはファイル/モジュール単位であって、クラス単位ではありません!!
各修飾子とアクセスレベルの対応は表のようになります。
アクセス修飾子 | アクセス可能範囲 |
---|---|
public | モジュールの外からもアクセスできる |
internal | モジュールの内部ならどこからでもアクセスできる |
private | 同じファイル内からのみアクセスできる |
なお、Swiftでいうところの「モジュール」とはザックリ言うとライブラリ(フレームワーク)です。
コードで見てみましょう。
Personクラスでは、name
変数やgreeting
変数はprivate
宣言されています。
にも関わらず、SampleClassの中から変数もメソッドもアクセスできてしまっています。エラーもワーニングも起きません。
AccessControlSample.swift
internal class SampleClass { internal func sampleMethod() { // インスタンス化する let taro :Person = Person(name: "Taro") let mary :Person = Person(name: "Mary") // プライベートメソッドを呼ぶ taro.greeting() //=> My name is Taro mary.greeting() //=> My name is Mary // プライベートインスタンス変数にアクセスする println("taro.name: \(taro.name)") //=> taro.name: Taro println("mary.name: \(mary.name)") //=> mary.name: Mary } } private class Person { private let name :String init(name: String) { self.name = name } private func greeting() { println("My name is \(self.name)") } }
これは、SampleClass
とPerson
を同一ファイルに記述したためです。
基本的には「1クラスにつき1ファイル」を記述するので、普段はあまり問題になりませんが。
デフォルトのアクセスレベル
明示的にアクセスレベルを指定しない場合はinternal
となります。
余談
公式ドキュメントに「ターゲットがひとつしかないアプリでは、デフォルトのInternalのママで大体事足りるから、アクセスレベルを明示的に指定しなくていいよー。まぁ、モジュール内の他のコードから実装隠したいときはprivate
付けておきなね。」的なことが書いてあります。
これは賛同しかねます。フレームワーク作者ではなくても、実装するクラスで「何がinternalで何がprivateなのか」はとても大事な情報だと思いますよ。
特に、Swiftではヘッダーファイルが無いため、「このクラスのAPIはどれなんだろう」というのが非常に分かりづらいです。 「ファイル外(≒クラス外)からアクセスすることを想定していない変数やメソッド」は全てprivate指定するほうがよいでしょう。
プライベート変数・メソッドはアンダースコアから始めるっていうコーディング規約が広まらないかなあ。