Objective-Cインスタンスでは、データはpublic
、protected
またはprivate
になります。例えば:
@interface Foo : NSObject
{
@public
int x;
@protected:
int y;
@private:
int z;
}
-(int) Apple;
-(int) pear;
-(int) banana;
@end
Swiftのリファレンスにアクセス修飾子についての言及はありません。 Swiftでデータの可視性を制限することは可能ですか?
Swift 3.0.1以降、4つのアクセスレベルがあります 、最高(最低制限)から最低(最高制限)までの順に説明します。
open
とpublic
エンティティを定義モジュール(ターゲット)の外部で使用できるようにします。フレームワークへのパブリックインタフェースを指定するときは、通常open
またはpublic
アクセスを使用します。
ただし、open
アクセスはクラスおよびクラスメンバーにのみ適用され、以下の点でpublic
アクセスと異なります。
public
クラスとクラスメンバーは、定義しているモジュール(ターゲット)内でのみサブクラス化してオーバーライドすることができます。open
クラスとクラスメンバーは、定義モジュール(ターゲット)の内部と外部の両方でサブクラス化してオーバーライドすることができます。// First.framework – A.Swift
open class A {}
// First.framework – B.Swift
public class B: A {} // ok
// Second.framework – C.Swift
import First
internal class C: A {} // ok
// Second.framework – D.Swift
import First
internal class D: B {} // error: B cannot be subclassed
internal
定義モジュール(ターゲット)内でエンティティを使用できるようにします。通常、アプリまたはフレームワークの内部構造を定義するときにはinternal
アクセスを使用します。
// First.framework – A.Swift
internal struct A {}
// First.framework – B.Swift
A() // ok
// Second.framework – C.Swift
import First
A() // error: A is unavailable
fileprivate
エンティティの使用をその定義元ファイルに限定します。通常、fileprivate
アクセスを使用して、特定の機能の実装詳細がファイル全体で使用されているときにそれらを隠します。
// First.framework – A.Swift
internal struct A {
fileprivate static let x: Int
}
A.x // ok
// First.framework – B.Swift
A.x // error: x is not available
private
エンティティーの使用をそれを包含する宣言に限定します。特定の機能の実装の詳細が単一の宣言内でのみ使用されている場合、それらの実装の詳細を隠すには通常private
アクセスを使用します。
// First.framework – A.Swift
internal struct A {
private static let x: Int
internal static func doSomethingWithX() {
x // ok
}
}
A.x // error: x is unavailable
Swift Documentation-Access Control で述べたように、Swiftには5 Access Controlsがあります:
openおよびpublic:モジュールのエンティティと、定義モジュールをインポートするモジュールのエンティティからアクセスできます。
internal:モジュールのエンティティからのみアクセスできます。これがデフォルトのアクセスレベルです。
fileprivateおよびprivate:それらを定義する限られた範囲内でのみ限定的にアクセスできます。
openは以前のバージョンのSwiftのpublicと同じであり、他のモジュールのクラスがそれらを使用および継承できるようにします。つまり、他のモジュールからサブクラス化できますモジュール。また、他のモジュールのメンバーがそれらを使用およびオーバーライドできるようにします。同じロジックがモジュールにも適用されます。
public他のモジュールのクラスはそれらを使用できますが、notはそれらを継承します。すなわち、それらは他のモジュールからサブクラス化することはできません。また、他のモジュールのメンバーはそれらを使用できますが、オーバーライドすることはできません。モジュールについては、同じオープンのロジックがあります(クラスはそれらを使用および継承できます。メンバーはそれらを使用およびオーバーライドできます)。
fileprivateは、ファイル全体からアクセスできます。
privateは、単一の宣言から、および同じファイル内にあるその宣言のextensionsからのみアクセスできます。例えば:
// Declaring "A" class that has the two types of "private" and "fileprivate":
class A {
private var aPrivate: String?
fileprivate var aFileprivate: String?
func accessMySelf() {
// this works fine
self.aPrivate = ""
self.aFileprivate = ""
}
}
// Declaring "B" for checking the abiltiy of accessing "A" class:
class B {
func accessA() {
// create an instance of "A" class
let aObject = A()
// Error! this is NOT accessable...
aObject.aPrivate = "I CANNOT set a value for it!"
// this works fine
aObject.aFileprivate = "I CAN set a value for it!"
}
}
SE-0169提案 で述べたように、Swift 4に追加された唯一の改良点は、privateアクセス制御スコープが同じファイル内のその宣言のextensionsからアクセスできるように展開されています。例えば:
struct MyStruct {
private let myMessage = "Hello World"
}
extension MyStruct {
func printMyMessage() {
print(myMessage)
// In Swift 3, you will get a compile time error:
// error: 'myMessage' is inaccessible due to 'private' protection level
// In Swift 4 it should works fine!
}
}
したがって、myMessage
をfileprivateとして宣言してファイル全体でアクセスできるようにする必要はありません。
SwiftやObjC(あるいはRubyやJavaなど)で "プライベートメソッド"を作ることについて話すとき、それらのメソッドは実際にはプライベートではありません。それらの周りに実際のアクセス制御はありません。ほんの少しのイントロスペクションを提供する言語であれば、開発者が必要に応じてクラスの外からこれらの値にアクセスできます。
ですから、ここで私たちが実際に話しているのは、私たちが望む機能を提示し、残りを "非公開"と見なすだけの "非公開"のインターフェイスを定義する方法です。
インターフェースを宣言するためのSwiftメカニズムはprotocol
であり、それはこの目的のために使用することができます。
protocol MyClass {
var publicProperty:Int {get set}
func publicMethod(foo:String)->String
}
class MyClassImplementation : MyClass {
var publicProperty:Int = 5
var privateProperty:Int = 8
func publicMethod(foo:String)->String{
return privateMethod(foo)
}
func privateMethod(foo:String)->String{
return "Hello \(foo)"
}
}
覚えておいて、プロトコルはファーストクラスのタイプであり、タイプができるところならどこでも使用することができます。 そして、このように使われると、それらはそれら自身のインターフェースを公開するだけで実装タイプのものを公開しません。
したがって、パラメータ型などでMyClass
の代わりにMyClassImplementation
を使用する限り、すべてうまくいくはずです。
func breakingAndEntering(foo:MyClass)->String{
return foo.privateMethod()
//ERROR: 'MyClass' does not have a member named 'privateMethod'
}
あなたがそれを推論するためにSwiftに頼るのではなくtypeで明示的にならなければならない直接代入のいくつかのケースがあります、しかしそれはほとんど取引ブレーカーのように思えません:
var myClass:MyClass = MyClassImplementation()
このようにプロトコルを使うことは意味論的で、かなり簡潔で、私の目にはObjCでこの目的のために使ってきたClass Extentionsのように見えます。
プロトコル、クロージャ、およびネストした/内部クラスの組み合わせを使用して、Swiftで情報を隠すためにモジュールパターンの線に沿って何かを使用することが可能です。読むのがすごくきれいでもいいとは言えませんが、うまくいきます。
例:
protocol HuhThing {
var huh: Int { get set }
}
func HuhMaker() -> HuhThing {
class InnerHuh: HuhThing {
var innerVal: Int = 0
var huh: Int {
get {
return mysteriousMath(innerVal)
}
set {
innerVal = newValue / 2
}
}
func mysteriousMath(number: Int) -> Int {
return number * 3 + 2
}
}
return InnerHuh()
}
HuhMaker()
var h = HuhMaker()
h.huh // 2
h.huh = 32
h.huh // 50
h.huh = 39
h.huh // 59
innerValとmysteriousMathは、ここでは外部の使用から隠されています。オブジェクトに向かって自分の道を掘るとエラーが発生するはずです。
私はSwiftのドキュメントを読んでいる過程の一部にすぎないので、ここに欠陥がある場合はそれを指摘してください、知りたいと思います。
Xcode 6 beta 4以降、Swiftにはアクセス修飾子があります。リリースノートから:
高速アクセス制御には、3つのアクセスレベルがあります。
- privateエンティティは、それらが定義されているソースファイル内からのみアクセスできます。
- 内部エンティティは、それらが定義されているターゲット内の任意の場所にアクセスできます。
- publicエンティティは、ターゲット内のどこからでも、また現在のターゲットのモジュールをインポートするその他のコンテキストからもアクセスできます。
暗黙のデフォルト値はinternal
なので、アプリケーションターゲット内では、より限定的にしたい場合を除き、アクセス修飾子をオフのままにすることができます。フレームワークターゲット(例えば、アプリと共有またはTodayビュー拡張の間でコードを共有するためのフレームワークを埋め込んでいる場合)では、public
を使用して、フレームワークのクライアントに公開するAPIを指定します。
Swift 3.0には5つの異なるアクセス制御があります。
オープンアクセスおよびパブリックアクセスにより、任意のソースファイル内でエンティティを使用できます。それらの定義モジュールから、そして定義モジュールをインポートする他のモジュールからのソースファイルでも。フレームワークへのパブリックインタフェースを指定するときは、通常、オープンアクセスまたはパブリックアクセスを使用します。
内部アクセスを使用すると、エンティティを定義元モジュールの任意のソースファイル内で使用できますが、そのモジュールの外側のソースファイルでは使用できません。通常、アプリまたはフレームワークの内部構造を定義するときに内部アクセスを使用します。
ファイル非公開アクセスは、エンティティの使用をそれ自身が定義しているソースファイルに制限します。ファイルプライベートアクセスを使用して、特定の機能の実装詳細がファイル全体で使用されているときにそれらを隠します。
プライベートアクセスは、エンティティーの使用をそれを囲む宣言に制限します。特定の機能の実装詳細が単一の宣言内でのみ使用されている場合は、その詳細を非表示にするためにプライベートアクセスを使用します。
オープンアクセスが最も高い(最も制限の少ない)アクセスレベルであり、プライベートアクセスが最も低い(最も制限的な)アクセスレベルです
デフォルトのアクセスレベル
明示的なアクセスレベルを自分で指定しないと、コード内のすべてのエンティティ(いくつかの特定の例外を除く)のデフォルトのアクセスレベルはinternalになります。その結果、多くの場合、コードで明示的なアクセスレベルを指定する必要はありません。
このトピックに関するリリースノート:
Publicとして宣言されたクラスは、その定義元モジュールの外部でサブクラス化できなくなり、publicとして宣言されたメソッドは、その定義元モジュールの外部でオーバーライドできなくなりました。クラスを外部でサブクラス化したり、メソッドを外部でオーバーライドしたりできるようにするには、それらをopenとして宣言します。これはpublicを超える新しいアクセスレベルです。インポートされたObjective-Cのクラスとメソッドは、すべてパブリックではなくオープンとしてインポートされるようになりました。 @testableインポートを使用してモジュールをインポートする単体テストでも、publicメソッドまたはinternalメソッドをオーバーライドするだけでなく、publicクラスまたは内部クラスをサブクラス化することもできます。 (SE-0117)
詳細情報と詳細: Swiftプログラミング言語(アクセス制御)
Beta 6のドキュメントには、3つの異なるアクセス修飾子があると記載されています。
そして、これら3つはクラス、プロトコル、機能、そしてプロパティに適用されます。
public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}
詳しくは、アクセス制御をご覧ください。
Swiftは、コード内のエンティティに対して3つの異なるアクセスレベルを提供します。これらのアクセスレベルは、エンティティが定義されているソースファイル、およびそのソースファイルが属するモジュールに関連しています。
- パブリックアクセス 定義モジュールからの任意のソースファイル内、および定義モジュールをインポートする別のモジュールからのソースファイル内でもエンティティを使用できます。フレームワークへのパブリックインタフェースを指定するときは、通常パブリックアクセスを使用します。
- 内部アクセス 定義元のモジュールからのソースファイル内ではエンティティを使用できますが、そのモジュール外のソースファイルではエンティティを使用できません。通常、アプリまたはフレームワークの内部構造を定義するときに内部アクセスを使用します。
- プライベートアクセス エンティティの使用をそれ自身が定義しているソースファイルに制限します。特定の機能の実装の詳細を隠すには、プライベートアクセスを使用してください。
パブリックアクセスは最も高い(最も制限の少ない)アクセスレベルであり、プライベートアクセスは最も低い(または最も制限の厳しい)アクセスレベルです。
デフォルトはそれを受け入れます internal 、そしてそのように指定される必要はありません。 private 指定子はクラスレベルではなく、ソースファイルレベルでnotを動作することにも注意してください。つまり、クラスの一部を本当に非公開にするには、独自のファイルに分割する必要があります。これはまた単体テストに関していくつかの興味深いケースを紹介します...
上記のリンクでコメントされている私がしたもう一つのポイントは、あなたがアクセスレベルを「アップグレード」することはできないということです。何かをサブクラス化した場合、それをさらに制限することができますが、その逆はできません。
この最後のビットは、関数、タプル、そして確かに他のものにも影響を与えます。つまり、もし関数が private classを使うのであれば、関数 internal または public を持つことは無効です彼らは private クラスにアクセスできない可能性があります。これはコンパイラの警告になります、そしてあなたは private 関数として関数を再宣言する必要があります。
ベータ4では、Swiftにアクセス修飾子を追加しました。
高速アクセス制御には、3つのアクセスレベルがあります。
private
エンティティは、それらが定義されているソースファイル内からのみアクセスできます。internal
エンティティは、それらが定義されているターゲット内の任意の場所にアクセスできます。public
エンティティは、ターゲット内のどこからでも、現在のターゲットのモジュールをインポートするその他のコンテキストからもアクセスできます。デフォルトでは、ソースファイル内のほとんどのエンティティに内部アクセス権があります。これにより、アプリケーション開発者はアクセス制御をほとんど無視しながら、フレームワーク開発者はフレームワークのAPIを完全に制御できます。
使用できるオプションの1つは、インスタンスの作成を関数にラップし、コンストラクタに適切なゲッターとセッターを提供することです。
class Counter {
let inc: () -> Int
let dec: () -> Int
init(start: Int) {
var n = start
inc = { ++n }
dec = { --n }
}
}
let c = Counter(start: 10)
c.inc() // 11
c.inc() // 12
c.dec() // 11
Swift 1〜3の場合
いいえ、できません。プライベートなメソッドや保護されたメソッドや変数はまったくありません。
すべてが公開されています。
更新 Swift 4以降、このスレッドで他の答えを見ることが可能です
Swift 3と4は、変数とメソッドのアクセスレベルにも大きな変化をもたらしました。 Swift 3と4には4つの異なるアクセスレベルがあります。open/publicaccessが最も高い(最も制限の少ない)アクセスレベルで、privateのアクセスが最も低い(最も制限が厳しい)アクセスレベルです。
おもしろい:
すべてのメソッドまたはメンバを "private"としてマークする代わりに、クラス/構造体の拡張でいくつかのメソッド(通常はヘルパー関数)をカバーして、その全体を "Private"としてマークすることができます。
class foo { }
private extension foo {
func somePrivateHelperFunction01() { }
func somePrivateHelperFunction02() { }
func somePrivateHelperFunction03() { }
}
より保守可能なコードを入手するために、これは良い考えです。また、1つのWordを変更するだけで、簡単に(例えば単体テストのために)非公開に切り替えることができます。
最もオープンなものから最も制限されたものへ:
open
は、そのモジュールをインポートするdefining moduleまたはany moduleの任意のソースファイルからopen
クラスおよびクラスメンバーにアクセスできます。定義モジュールとそのモジュールをインポートするモジュールの両方で、open
クラスをサブクラス化するか、open
クラスメンバーをオーバーライドできます。
public
は、open
と同じアクセスを許可します-任意のモジュールの任意のソースファイル-ただし、より多くのrestrictiveサブクラス化とオーバーライドがあります。 同じモジュール内でのみpublic
クラスをサブクラス化できます。 public
クラスメンバは、同じモジュールのサブクラスによってのみオーバーライドできます。これは、フレームワークを作成している場合に重要です。そのフレームワークのユーザーがクラスをサブクラス化またはメソッドをオーバーライドできるようにする場合は、open
にする必要があります。
internal
は、defining module内の任意のソースファイルからの使用を許可しますが、そのモジュールの外部からは許可しません。これはdefaultアクセスレベルです。
fileprivate
は、定義するソースファイル内でのみ使用できます。
private
は、同じソースファイル内のその宣言の任意の拡張に対して、囲む宣言およびSwift 4の新しい宣言からのみ使用できます。
続きを読む こちら
言語文法 には、キーワード 'public'、 'private'、または 'protected'はありません。これはすべてが公にされていることを示唆しています。もちろん、これらのキーワードを使用せずにアクセス修飾子を指定する方法はいくつかありますが、言語リファレンスには見つかりませんでした。
保護されたメソッドに似たものが欲しい人のために時間を節約することを願っています:
他の答えと同様に、Swiftは現在 'private'修飾子を提供しています - これは例えばJavaやC#のようにクラスごとではなくファイルごとに定義されています。つまり、保護されたメソッドが必要な場合は、それらが同じファイル内にある場合はSwiftのプライベートメソッドで実行できます。
例えばファイル1:
class BaseClass {
private func protectedMethod() {
}
}
class SubClass : BaseClass {
func publicMethod() {
self.protectedMethod() //this is ok as they are in same file
}
}
ファイル2:
func test() {
var a = BaseClass()
a.protectedMethod() //ERROR
var b = SubClass()
b.protectedMethod() //ERROR
}
class SubClass2 : BaseClass {
func publicMethod() {
self.protectedMethod() //ERROR
}
}