アクセス制御の概念は、型、関数、および他の宣言が他のコードによってアクセスされる方法を制限することを可能にします。 Swiftは五つの異なるレベルのアクセス制御を提供しており、それらをフルに活用することは、明確に分離された懸念と堅牢な構造を持つプログラムをSwiftで新しい型、プロパティ、または関数を定義すると、デフォルトではinternalアクセスレベルがあります。 つまり、アプリ、システム拡張機能、フレームワーク、Swiftパッケージなど、同じモジュール内に存在する他のすべてのコードに表示されます。

例として、ショッピングアプリを構築していて、商品の配列の合計価格を計算できるPriceCalculatorというクラスを定義したとします。

現在、明示的なアクセスレベルを指定していないため、PriceCalculatorクラス(およびそのcalculatePriceメソッド)はアプリ内のどこからでもアクセスできます。 しかし、新しいクラスを他のモジュールと共有しようとしている場合(例えば、メインアプリと拡張機能、またはコンパニオンApple Watchアプリの間で共有するフ 定義されているモジュールの外でクラスを見つけることができましたが、その(暗黙の)初期化子は他のコードと同じようにデフォルトでinternalであるため、そ これを修正するには、public初期化子を定義しましょう。:

public class PriceCalculator { public init() {} ...}

これで、モジュールの内側と外側の両方でPriceCalculatorを見つけ、初期化し、呼び出すことができます—fantastic。 しかし、今、我々はまた、それを変更したり、それに新しい機能を追加するためにそれをサブクラス化するために探しているとしましょう。 それは現在、独自のモジュール内で可能ですが、それは再びそれの外で防止されているものです。これを変更するには、Swiftの現在最もオープンなレベルのアクセス制御を使用する必要があります。open:

open class PriceCalculator { ...}

上記の変更により、新しい初期化子、新しいプロパティ、新しいメソッドを持つことができるPriceCalculatoranywhereのカスタムサブクラスを作成できるようになりま これを使用してDiscountedPriceCalculatorを実装し、指定されたdiscountをすべての価格計算に適用できるようにする方法は次のとおりです:

上記では、新しい価格計算メソッドを定義していますが、代わりに基本クラスから継承した既存のcalculatePriceメソッドを上書きして変更する方がはるかに適 そうすれば、どのメソッドを呼び出すのか混乱することはなく、2つのクラスの一貫性を保つことができます。

これを行うには、元の宣言—今回はcalculatePriceメソッド宣言—を次のようにマークする必要がありますopen:

open class PriceCalculator { public init() {} open func calculatePrice(for products: ) -> Int { ... }}

上記のようにして、別のメソッドを作成するのではなく、calculatePriceを自由にオーバーライドできるようになりました:

それはinternalpublicopenです—これは、公共の使用と変更のために徐々に宣言を開くために使用されます。 しかし、もちろん、他の方法に進み、コードの一部が発見されて使用されないようにすることもできます。 最初は、それを行う上での価値が何であるか疑問に思えるかもしれませんが、それは本当に私たちのAPIをはるかに狭く、集中させるのに役立ちます。

それでは、アクセスレベルスペクトラムの反対側に行き、最も制限的なレベル—privateを見てみましょう。 privateとマークされている型、プロパティ、またはメソッドは、それ自身の型(同じファイル内で定義されている型の拡張子も含む)内でのみ表示されます。

指定された型のプライベート実装の詳細とみなされるべきものは、間違いなくprivateとしてマークされるべきです。 たとえば、以前のprice calculatorのdiscountプロパティは、実際には独自のクラス内でのみ使用されることを意図していたため、先に進んでそのプロパティを非公開にし:

class DiscountedPriceCalculator: PriceCalculator { private let discount: Int ...}

以前の実装は、discountDiscountedPriceCalculatorクラス内で完全に表示されるため、以前とまったく同じように動作し続けます。 ただし、同じファイル内で定義されている他の型も含めるようにその可視性を少し拡張したい場合は、fileprivateを使用する必要があります。fileprivateは、それがどのよ:

class DiscountedPriceCalculator: PriceCalculator { fileprivate let discount: Int ...}

上記の変更により、同じファイルで定義されている関連コードからdiscountプロパティにアクセスできるようになりました。UIAlertControllerのこの拡張機能のように、アラート内の製品の配列の価格説明を簡単に表示できます。

無料の関数、タイプ、拡張機能に関しては、privatefileprivateはまったく同じように動作します。 これらは、型内で定義されている宣言に適用される場合にのみ異なります。要約すると、これらはSwiftが現在提供している5つのレベルのアクセス制御です:

  • private プロパティまたは関数を、同じファイル内で定義されているその型の拡張子を含む、その囲む型内でプライベートに保持します。 トップレベルの型、関数、または拡張に適用すると、fileprivateと同じように動作します。
  • fileprivateは、定義されているファイル全体の中で宣言を可視化し、他のすべてのコードから宣言を非表示にします。
  • internalはデフォルトのアクセスレベルであり、宣言が定義されているモジュール全体内で表示されます。
  • publicは、モジュールの外側の関数、型、拡張子、またはプロパティを明らかにします。
  • openは、モジュールの外部でクラスをサブクラス化し、関数またはプロパティをオーバーライドできるようにします。

一般に、特定の宣言が実際に持つことができる最も制限的なレベルのアクセスから始め、必要に応じて後で開くことをお勧めします。 そうすれば、さまざまなタイプと機能の間の相互作用の道を制限していますが、最初は悪いことのように見えるかもしれませんが、保守可能で構造化されたシステムを構築するためには本当に不可欠なことがよくあります。

読んでくれてありがとう! 🚀

(この記事では、private(set)などの突然変異固有のアクセス修飾子には含まれていないことに注意してください。 これらは、将来的には別の基本の記事でカバーされます。)

このスポンサーをチェックアウトすることにより、サンデルによってスウィフトをサポ:

Instabug: Instabugが各バグレポートに自動的に添付する詳細なスタックトレース、ネットワークログ、UIイベントを使用して、バグ、クラッシュ、その他の問題をはるかに高速に解決します。 私と世界中の何千ものiOS開発チームの両方で使用されています。 無料で試してみて、コードの単一行だけでそれを統合します。

コメントを残す

メールアドレスが公開されることはありません。