Swift3でfileprivateとprivateを区別する良い例は何ですか


142

この記事は、の新しいアクセス指定子を理解するのに役立ちましたSwift 3。また、fileprivateおよびのさまざまな使用例も示しprivateます。

私の質問は- fileprivateこのファイルでのみ使用される関数で使用するのと同じprivateですか?

回答:


282

fileprivateこれはprivate、以前のSwiftリリースで使用されていたものです。同じソースファイルからアクセスできます。としてマークされた宣言は、宣言されprivateたレキシカルスコープ内でのみアクセスできるようになりました。そのprivateため、よりも制限されfileprivateます。

とおりスウィフト4、拡張子が同じソースファイルで定義されている場合タイプ内部のプライベートな宣言は、同じタイプの拡張にアクセスできます。

例(すべて1つのソースファイル内):

class A {
    private func foo() {}
    fileprivate func bar() {}

    func baz() {
        foo()
        bar()
    }
}

extension A {
    func test() {
        foo() // Swift 3: error: use of unresolved identifier 'foo'
              // Swift 4: no error because extension is in same source file
        bar()
    }
}

let a = A()
a.foo() // error: 'foo' is inaccessible due to 'private' protection level
a.bar()
  • プライベートfooメソッドには、class A { ... }定義のスコープ内でのみアクセスできます。タイプの拡張機能からもアクセスできません(Swift 3では、Swift 4での変更点については、下の2番目のメモを参照してください)。

  • file-private barメソッドは、同じソースファイルからアクセスできます。

ノート:

  1. 提案SE-0159 – Swift 4でSwift 2のセマンティクスに戻すよう提案されたプライベートアクセスレベルを修正しました。Swift-evolutionメーリングリストでの長く議論の多い議論の後、提案は拒否されました

  2. 提案SE-0169 –プライベート宣言と拡張間の相互作用を改善private するは、拡張が同じソースファイルで定義されている場合、同じ型の拡張からアクセスできる型内の宣言を作成することを提案します。 この提案はSwift 4で受け入れられ、実装されました。


2
コードをSwift 2から3に自動的に変換する場合、Xcodeはにprivateなりfileprivateます。あなたが手でそれを行うことの贅沢を持っている場合は、あなたは、多くの場合、残しての恩恵を受けることができるprivateようprivate...それは、すべての良いをコンパイルする場合。
Dan Rosenstark 2017年

@DanielLarsson:編集の提案を再確認してください:両方のコメントがfoo()通話に適用されます。
マーティンR

82

私は、privatefileprivateopenpublicについての図を描くだけです

テキストの説明については、Martin Rの回答を参照してください

[Swift 4を更新]

ここに画像の説明を入力してください


9
気をつけて、fileprivate拡張子にリンクされていませんが、ファイルにリンクされています(クラスAの拡張子を別のファイルに書き込んでも、fileprivateメンバーの使用は許可されません)
Vince

1
これは間違っているようです。重要なポイントがありません。同じモジュール内のクラスと異なるモジュール内のクラスを区別する必要があります。それらが異なるモジュールにあるpublic場合、継承を許可しないため、3番目のイメージは正しくありません。また、拡張機能が表示されている場合は、いつでも任意のクラスに拡張機能を配置できます。その場合、拡張機能の可視性を説明することはあまり良い考えではありません。
スルタン2017

実際、図は同じモジュールでのみ機能するので、3番目の画像では、fileprivateが同じファイルでのみ機能することをユーザーにすばやく理解してもらいたいと思います。
Stephen Chen

6

実際の経験則では、クラス/構造体の宣言内でのみ使用される変数、定数、内部構造体、およびクラスにプライベートを使用します。class / structと同じファイル内の拡張機能の内部で使用されているが、それらの定義中括弧(つまり、レキシカルスコープ)の外部で使用されるものには、fileprivateを使用します。

    class ViewController: UIViewController {
        @IBOutlet var tableView: UITableView!
        //This is not used outside of class Viewcontroller
        private var titleText = "Demo"
        //This gets used in the extension
        fileprivate var list = [String]()
        override func viewDidLoad() {
            navigationItem.title = titleText
        }
    }

    extension ViewController: UITableViewDataSource {
        func numberOfSections(in tableView: UITableView) -> Int {
            return list.count
        }
    }

6

Swift 4.0では、Privateが拡張機能でアクセスできますが、同じファイル内にあります。他のファイルで拡張子を宣言/定義すると、プライベート変数は拡張子にアクセスできなくなります**

ファイルプライベート
ファイルプライベートアクセスは、エンティティの使用をそれ自体の定義ソースファイルに制限します。ファイルプライベートアクセスを使用して、特定の機能の実装の詳細がファイル全体で使用されている場合に、それらの詳細を非表示にします。
構文: fileprivate <var type> <variable name>
例: fileprivate class SomeFilePrivateClass {}


プライベート
プライベートアクセスは、エンティティの使用を、囲んでいる宣言、および同じファイル内にあるその宣言の拡張に制限します。特定の機能の実装の詳細が単一の宣言内でのみ使用される場合は、プライベートアクセスを使用して、特定の機能の実装の詳細を非表示にします。
構文: private <var type> <variable name>
例: private class SomePrivateClass {}


すべてのアクセスレベルの詳細は次のとおりです。Swift-アクセスレベル

この画像を見てください:
ファイル: ViewController.swift
ここでは、拡張機能とビューコントローラーの両方が同じファイルにあるためtestPrivateAccessLevel、拡張機能でプライベート変数にアクセスできます。

ここに画像の説明を入力してください


ファイル: TestFile.swift
ここでは、拡張機能とビューコントローラーの両方が異なるファイルにあるためtestPrivateAccessLevel、拡張機能ではプライベート変数にアクセスできません。

ここに画像の説明を入力してください

ここに画像の説明を入力してください


ここで、クラスViewController2はのサブクラスでViewControllerあり、両方が同じファイルにあります。ここで、プライベート変数testPrivateAccessLevelはサブクラスではアクセスできませんが、fileprivateはサブクラスでアクセスできます。

ここに画像の説明を入力してください


5

@MartinRと@StephenChenの答えは完璧ですが、Swift 4は少し変更を加えています。

Privateは、それが宣言されているクラスおよびその拡張に対してプライベートであると見なされます。

FilePrivateは、変数が定義されているクラス、その拡張子、または同じファイルで定義されているその他のクラスのいずれであっても、そのファイルではプライベートであると見なされます。


5

Swift 5用に更新

プライベート vs FilePrivate

より明確にするために、コードスニペットをPlaygroundに貼り付けます

class Sum1 {
    let a: Int!
    let b: Int!
    private var result: Int?
    fileprivate var resultt: Int?

    init(a : Int, b: Int) {
        self.a = a
        self.b = b
    }

    func sum(){
        result = a + b
        print(result as! Int)
    }
}

let aObj = Sum1.init(a: 10, b: 20)
aObj.sum()
aObj.resultt //File Private Accessible as inside same swift file
aObj.result //Private varaible will not be accessible outside its definition except extensions

extension Sum1{

    func testing() {

        // Both private and fileprivate accessible in extensions
        print(result)
        print(resultt)
    }
}

//If SUM2 class is created in same file as Sum1 ---
class Sum2{

    func test(){

        let aSum1 = Sum1.init(a: 2, b: 2)
        // Only file private accessible
        aSum1.resultt

    }
}

:Swiftファイルの外では、privateとfileprivateの両方にアクセスできません。


4

filePrivate-アクセス制御レベルはファイル内にあります。

ケース1:同じクラスファイルで拡張子を作成し、その拡張子でfileprivate関数またはfileprivateプロパティにアクセスしようとした
場合 -アクセス許可ケース2:新しいファイルでクラスの拡張子を作成した場合-そして、fileprivate関数またはfileprivateにアクセスしようとしますプロパティ-アクセスは許可されていません

private-アクセス制御レベルはレキシカルスコープ内にあります

ケース1:プロパティまたは関数がクラスでプライベートとして宣言されている場合、スコープはデフォルトでクラスになります。 ケース2:プライベートインスタンスが関数本体で宣言されている場合-インスタンスのスコープは関数本体に限定されます。


3

次の例では、によって変更されprivatefileprivate同じように動作するように見える言語構造:

fileprivate func fact(_ n: Int) -> Int {
    if (n == 0) {
        return 1
    } else {
        return n * fact(n - 1)
    }
}

private func gauss(_ n: Int) -> Int {
    if (n == 0) {
        return 0
    } else {
        return n + gauss(n - 1)
    }
}

print(fact(0))
print(fact(5))
print(fact(3))

print(gauss(10))
print(gauss(9))

これは直感によると思います。しかし、例外はありますか?

よろしくお願いします。


3

これはswift 4の説明です。swift3の違いはプライベートです。swift 3 privateは、その拡張機能ではアクセスできません。クラスA自体のみがアクセスできます。

ここに画像の説明を入力してください 迅速な4の後、人は通常同じファイルでサブクラスを定義しないため、fileprivateは少し冗長になります。ほとんどの場合、プライベートで十分です。


1
class Privacy {

    fileprivate(set) var pu:Int {
        get {
            return self.pr
        }
        set {
            self.pr = newValue
        }
    }
    private var pr:Int = 0
    fileprivate var fp:Int = 0


    func ex() {
        print("\(self.pu) == \(self.pr) and not \(self.fp)")
    }
}


extension Privacy {

    func ex2() {
        self.pu = 5
        self.ex()
    }

}

ivarは非常にシンプルなので、私はこれが好きです。

fileprivateをprivate(およびその逆)に変更して、コンパイル時に何が起こるかを確認してください...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.