この 記事 は、Swift 3
の新しいアクセス指定子を理解するのに役立ちました。また、fileprivate
およびprivate
のさまざまな使用法の例を示します。
私の質問は-fileprivate
を使用するのと同じように、このファイルでのみ使用される関数でprivate
を使用していないのですか?
fileprivate
は、以前のSwiftリリースで使用されていたprivate
になりました。同じソースファイルからアクセスできます。 private
としてマークされた宣言は、宣言されたレキシカルスコープ内でのみアクセスできるようになりました。したがって、private
はfileprivate
よりも制限が厳しくなります。
Swift 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番目の注意を参照してください)。
ファイルプライベートbar
メソッドは、同じソースファイルからアクセスできます。
注:
提案 SE-0159 –プライベートアクセスレベルの修正 SwiftのSwift 2セマンティクスに戻すことを提案しました。 -evolutionメーリングリスト、提案は 拒否 でした。
提案 SE-0169 –プライベート宣言と拡張機能間の相互作用の改善 は、拡張機能がsameで定義されている場合、同じ型の拡張機能がアクセスできる型内のprivate
宣言を作成することを提案しますソースファイル。この提案はSwiftで受け入れられ、実装されました4。
実用的な経験則として、クラス/構造体の宣言内でのみ使用される変数、定数、内部構造体、およびクラスにはprivateを使用します。 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
}
}
Swift 4.0では、プライベートで同じファイル内の拡張子でアクセスできるようになりました。他のファイルで拡張機能を宣言/定義すると、プライベート変数は拡張機能からアクセスできなくなります**
ファイルプライベート
ファイルプライベートアクセスは、エンティティの使用を独自の定義ソースファイルに制限します。ファイルプライベートアクセスを使用して、特定の機能の詳細がファイル全体で使用されている場合、それらの詳細を非表示にします。
構文:fileprivate <var type> <variable name>
例:fileprivate class SomeFilePrivateClass {}
プライベート
プライベートアクセスは、エンティティの使用を囲んでいる宣言と、同じファイル内のその宣言の拡張に制限します。プライベートアクセスを使用して、特定の機能の実装の詳細を隠しますこれらの詳細は、単一の宣言内でのみ使用されます。
構文:private <var type> <variable name>
例:private class SomePrivateClass {}
すべてのアクセスレベルの詳細を次に示します。 Swift-Access Levels
この画像を見てください:
ファイル:ViewController.Swift
ここで、拡張機能とView Controllerは両方とも同じファイルにあるため、プライベート変数testPrivateAccessLevel
は拡張機能でアクセス可能です
ファイル:TestFile.Swift
ここで、拡張機能とView Controllerは両方とも異なるファイルにあるため、プライベート変数testPrivateAccessLevel
は拡張機能ではアクセスできません。
ここで、クラスViewController2
はViewController
のサブクラスであり、両方が同じファイルにあります。ここで、プライベート変数testPrivateAccessLevel
はサブクラスではアクセスできませんが、fileprivateはサブクラスでアクセスできます。
@MartinRと@StephenChenの答えは完璧ですが、Swift 4は物事を少し変えます。
Privateは、宣言されたクラスおよびその拡張に対してプライベートと見なされるようになりました。
FilePrivateは、変数が定義されているクラス、その拡張子、または同じファイルで定義されている他のクラスであっても、そのファイルではプライベートと見なされます。
次の例では、private
およびfileprivate
によって変更された言語構成体は、同じように動作するようです。
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))
これは直感によると思います。しかし、例外はありますか?
よろしくお願いします。
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の両方にアクセスできません。
filePrivate-アクセス制御レベルはファイル内にあります。
ケース1:同じクラスファイルで拡張機能を作成し、その拡張機能でfileprivate関数またはfileprivateプロパティにアクセスしようとした場合-アクセスが許可されました
ケース2:新しいファイルにクラスの拡張子を作成する場合-そして、今度はfileprivate関数またはfileprivateプロパティにアクセスしてください-アクセスは許可されません
プライベート-アクセス制御レベルはレキシカルスコープ内にあります
ケース1:プロパティまたは関数がクラスでプライベートとして宣言されている場合-スコープはデフォルトでクラスです。 ケース2:プライベートインスタンスが関数本体で宣言されている場合-インスタンスのスコープは関数本体に制限されます。
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(またはその逆)に変更してみて、コンパイル時に何が起こるかを確認してください...