web-dev-qa-db-ja.com

Swiftにはアクセス修飾子がありますか?

Objective-Cインスタンスでは、データはpublicprotectedまたはprivateになります。例えば:

@interface Foo : NSObject
{
  @public
    int x;
  @protected:
    int y;
  @private:
    int z;
  }
-(int) Apple;
-(int) pear;
-(int) banana;
@end

Swiftのリファレンスにアクセス修飾子についての言及はありません。 Swiftでデータの可視性を制限することは可能ですか?

265
Gergo Erdosi

Swift 3.0.1以降、4つのアクセスレベルがあります 、最高(最低制限)から最低(最高制限)までの順に説明します。


1. openpublic

エンティティを定義モジュール(ターゲット)の外部で使用できるようにします。フレームワークへのパブリックインタフェースを指定するときは、通常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

2. 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

3. 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

4. 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
402
akashivskyy

スウィフト4/Swift 5

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



Swift 3とSwift 4アクセス制御の違いは何ですか?

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!
    }
}

したがって、myMessagefileprivateとして宣言してファイル全体でアクセスできるようにする必要はありません。

20
Ahmad F

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のように見えます。

17
jemmons

私が言える限りでは、「公開」、「非公開」、または「保護」というキーワードはありません。これはすべてが公にされていることを示唆しています。

しかし、Appleは人々が“ プロトコル ”(他の国々ではインターフェースと呼ばれる)と 工場設計パターン を使って実装タイプの詳細を隠すことを期待するかもしれません。

これはとにかく使用するのに良いデザインパターンです。 論理を維持しながら、実装のクラス階層を変更できるため型システムも同じです。

15
Ian Ringrose

プロトコル、クロージャ、およびネストした/内部クラスの組み合わせを使用して、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のドキュメントを読んでいる過程の一部にすぎないので、ここに欠陥がある場合はそれを指摘してください、知りたいと思います。

12
Dave Kapp

Xcode 6 beta 4以降、Swiftにはアクセス修飾子があります。リリースノートから:

高速アクセス制御には、3つのアクセスレベルがあります。

  • privateエンティティは、それらが定義されているソースファイル内からのみアクセスできます。
  • 内部エンティティは、それらが定義されているターゲット内の任意の場所にアクセスできます。
  • publicエンティティは、ターゲット内のどこからでも、また現在のターゲットのモジュールをインポートするその他のコンテキストからもアクセスできます。

暗黙のデフォルト値はinternalなので、アプリケーションターゲット内では、より限定的にしたい場合を除き、アクセス修飾子をオフのままにすることができます。フレームワークターゲット(例えば、アプリと共有またはTodayビュー拡張の間でコードを共有するためのフレームワークを埋め込んでいる場合)では、publicを使用して、フレームワークのクライアントに公開するAPIを指定します。

9
rickster

Swift 3.0には5つの異なるアクセス制御があります。

  1. 開いた
  2. パブリック
  3. 内部
  4. fileprivate
  5. 非公開

オープンアクセスおよびパブリックアクセスにより、任意のソースファイル内でエンティティを使用できます。それらの定義モジュールから、そして定義モジュールをインポートする他のモジュールからのソースファイルでも。フレームワークへのパブリックインタフェースを指定するときは、通常、オープンアクセスまたはパブリックアクセスを使用します。

内部アクセスを使用すると、エンティティを定義元モジュールの任意のソースファイル内で使用できますが、そのモジュールの外側のソースファイルでは使用できません。通常、アプリまたはフレームワークの内部構造を定義するときに内部アクセスを使用します。

ファイル非公開アクセスは、エンティティの使用をそれ自身が定義しているソースファイルに制限します。ファイルプライベートアクセスを使用して、特定の機能の実装詳細がファイル全体で使用されているときにそれらを隠します。

プライベートアクセスは、エンティティーの使用をそれを囲む宣言に制限します。特定の機能の実装詳細が単一の宣言内でのみ使用されている場合は、その詳細を非表示にするためにプライベートアクセスを使用します。

オープンアクセスが最も高い(最も制限の少ない)アクセスレベルであり、プライベートアクセスが最も低い(最も制限的な)アクセスレベルです

デフォルトのアクセスレベル

明示的なアクセスレベルを自分で指定しないと、コード内のすべてのエンティティ(いくつかの特定の例外を除く)のデフォルトのアクセスレベルはinternalになります。その結果、多くの場合、コードで明示的なアクセスレベルを指定する必要はありません。

このトピックに関するリリースノート:

Publicとして宣言されたクラスは、その定義元モジュールの外部でサブクラス化できなくなり、publicとして宣言されたメソッドは、その定義元モジュールの外部でオーバーライドできなくなりました。クラスを外部でサブクラス化したり、メソッドを外部でオーバーライドしたりできるようにするには、それらをopenとして宣言します。これはpublicを超える新しいアクセスレベルです。インポートされたObjective-Cのクラスとメソッドは、すべてパブリックではなくオープンとしてインポートされるようになりました。 @testableインポートを使用してモジュールをインポートする単体テストでも、publicメソッドまたはinternalメソッドをオーバーライドするだけでなく、publicクラスまたは内部クラスをサブクラス化することもできます。 (SE-0117)

詳細情報と詳細: Swiftプログラミング言語(アクセス制御)

6
CryingHippo

Beta 6のドキュメントには、3つの異なるアクセス修飾子があると記載されています。

  • パブリック
  • 内部
  • 非公開

そして、これら3つはクラス、プロトコル、機能、そしてプロパティに適用されます。

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

詳しくは、アクセス制御をご覧ください。

4
OliverAssad

アクセス制御メカニズムは Xcode 6で導入されました

Swiftは、コード内のエンティティに対して3つの異なるアクセスレベルを提供します。これらのアクセスレベルは、エンティティが定義されているソースファイル、およびそのソースファイルが属するモジュールに関連しています。

  • パブリックアクセス 定義モジュールからの任意のソースファイル内、および定義モジュールをインポートする別のモジュールからのソースファイル内でもエンティティを使用できます。フレームワークへのパブリックインタフェースを指定するときは、通常パブリックアクセスを使用します。
  • 内部アクセス 定義元のモジュールからのソースファイル内ではエンティティを使用できますが、そのモジュール外のソースファイルではエンティティを使用できません。通常、アプリまたはフレームワークの内部構造を定義するときに内部アクセスを使用します。
  • プライベートアクセス エンティティの使用をそれ自身が定義しているソースファイルに制限します。特定の機能の実装の詳細を隠すには、プライベートアクセスを使用してください。

パブリックアクセスは最も高い(最も制限の少ない)アクセスレベルであり、プライベートアクセスは最も低い(または最も制限の厳しい)アクセスレベルです。

デフォルトはそれを受け入れます internal 、そしてそのように指定される必要はありません。 private 指定子はクラスレベルではなく、ソースファイルレベルでnotを動作することにも注意してください。つまり、クラスの一部を本当に非公開にするには、独自のファイルに分割する必要があります。これはまた単体テストに関していくつかの興味深いケースを紹介します...

上記のリンクでコメントされている私がしたもう一つのポイントは、あなたがアクセスレベルを「アップグレード」することはできないということです。何かをサブクラス化した場合、それをさらに制限することができますが、その逆はできません。

この最後のビットは、関数、タプル、そして確かに他のものにも影響を与えます。つまり、もし関数が private classを使うのであれば、関数 internal または public を持つことは無効です彼らは private クラスにアクセスできない可能性があります。これはコンパイラの警告になります、そしてあなたは private 関数として関数を再宣言する必要があります。

3
holroy

ベータ4では、Swiftにアクセス修飾子を追加しました。

から Xcode 6 beta 4リリースノート

高速アクセス制御には、3つのアクセスレベルがあります。

  • privateエンティティは、それらが定義されているソースファイル内からのみアクセスできます。
  • internalエンティティは、それらが定義されているターゲット内の任意の場所にアクセスできます。
  • publicエンティティは、ターゲット内のどこからでも、現在のターゲットのモジュールをインポートするその他のコンテキストからもアクセスできます。

デフォルトでは、ソースファイル内のほとんどのエンティティに内部アクセス権があります。これにより、アプリケーション開発者はアクセス制御をほとんど無視しながら、フレームワーク開発者はフレームワークのAPIを完全に制御できます。

2

使用できるオプションの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以降、このスレッドで他の答えを見ることが可能です

2
Sam

Swift 3と4は、変数とメソッドのアクセスレベルにも大きな変化をもたらしました。 Swift 3と4には4つの異なるアクセスレベルがあります。open/publicaccessが最も高い(最も制限の少ない)アクセスレベルで、privateのアクセスが最も低い(最も制限が厳しい)アクセスレベルです。

  • privateの関数とメンバーは、エンティティ自身(struct、class、…)とその拡張(Swift 3でも同様)の範囲内からしかアクセスできません。拡張機能が制限されていました)
  • fileprivate関数およびメンバーは、宣言されているソースファイル内からのみアクセスできます。
  • 内部関数とメンバ(アクセスレベルのキーを明示的に追加しない場合はデフォルトであるWord)は、ターゲット内のどこにでもアクセスできます。定義済み。 TestTargetがすべてのソースに自動的にアクセスするわけではない理由は、xCodeのファイルインスペクタでアクセス可能としてマークされている必要があるからです。
  • 公開または公開関数およびメンバーは、ターゲット内の任意の場所から、および現在のターゲットのモジュールをインポートするその他のコンテキストからアクセスできます。

おもしろい:

すべてのメソッドまたはメンバを "private"としてマークする代わりに、クラス/構造体の拡張でいくつかのメソッド(通常はヘルパー関数)をカバーして、その全体を "Private"としてマークすることができます。

class foo { }

private extension foo {
    func somePrivateHelperFunction01() { }
    func somePrivateHelperFunction02() { }
    func somePrivateHelperFunction03() { }
}

より保守可能なコードを入手するために、これは良い考えです。また、1つのWordを変更するだけで、簡単に(例えば単体テストのために)非公開に切り替えることができます。

アップルのドキュメント

2
LukeSideWalker

enter image description here

最もオープンなものから最も制限されたものへ:

  • openは、そのモジュールをインポートするdefining moduleまたはany moduleの任意のソースファイルからopenクラスおよびクラスメンバーにアクセスできます。定義モジュールとそのモジュールをインポートするモジュールの両方で、openクラスをサブクラス化するか、openクラスメンバーをオーバーライドできます。

  • publicは、openと同じアクセスを許可します-任意のモジュールの任意のソースファイル-ただし、より多くのrestrictiveサブクラス化とオーバーライドがあります。 同じモジュール内でのみpublicクラスをサブクラス化できます。 publicクラスメンバは、同じモジュールのサブクラスによってのみオーバーライドできます。これは、フレームワークを作成している場合に重要です。そのフレームワークのユーザーがクラスをサブクラス化またはメソッドをオーバーライドできるようにする場合は、openにする必要があります。

  • internalは、defining module内の任意のソースファイルからの使用を許可しますが、そのモジュールの外部からは許可しません。これはdefaultアクセスレベルです。

  • fileprivateは、定義するソースファイル内でのみ使用できます。

  • privateは、同じソースファイル内のその宣言の任意の拡張に対して、囲む宣言およびSwift 4の新しい宣言からのみ使用できます。

続きを読む こちら

1
yoAlex5

言語文法 には、キーワード 'public'、 'private'、または 'protected'はありません。これはすべてが公にされていることを示唆しています。もちろん、これらのキーワードを使用せずにアクセス修飾子を指定する方法はいくつかありますが、言語リファレンスには見つかりませんでした。

1
Scroog1

保護されたメソッドに似たものが欲しい人のために時間を節約することを願っています:

他の答えと同様に、Swiftは現在 'private'修飾子を提供しています - これは例えばJavaやC#のようにクラスごとではなくファイルごとに定義されています。つまり、保護されたメソッドが必要な場合は、それらが同じファイル内にある場合はSwiftのプライベートメソッドで実行できます

  1. 「保護された」メソッドを保持するための基本クラスを作成します(実際にはプライベート)。
  2. このクラスをサブクラス化して同じメソッドを使用する
  3. 他のファイルでは、サブクラス化した場合でも基本クラスのメソッドにアクセスできません。

例えばファイル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
    }

}

0
james_alvarez
0
OliverAssad