文書   >   Swift   >   構造体とクラスの選択
記事
構造体とクラスの選択
データとモデルの動作を保存する方法を決定します。
概要
構造体とクラスは、データを格納してアプリ内の動作をモデル化するのに適していますが、それらが類似していると、一方を選択するのが難しくなります。
以下の推奨事項を考慮して、新しいデータ型をアプリに追加するときにどちらのオプションが適切かを選択してください。
- デフォルトでは構造体を使用してください。
- Objective-C との相互運用性が必要な場合はクラスを使用してください。
- モデル化しているデータの ID を制御する必要がある場合は、クラスを使用してください。
- 実装を共有して動作を採用するためにプロトコルと一緒に構造体を使用してください。
デフォルトでは構造体を使用してください。
一般的な種類のデータを表すには構造体を使用してください。Swift の構造体には、他の言語のクラスに限定されている多くの機能が含まれています。それらには、保管されたプロパティ、計算プロパティ、およびメソッドを含みます。さらに、Swift の構造体には、デフォルトの実装を通じて動作を得るためのプロトコルを採用できます。Swift 標準ライブラリと Foundation は、数字、文字列、配列、辞書など、頻繁に使用する型に構造体を使用しています。
構造体を使用すると、アプリの全体的な状態を考慮する必要なく、コードの一部について推論するのが簡単になります。構造体は値型なので (クラスとは異なり)、構造体へのローカルな変更は、アプリのフローの一部として意図的にそれらの変更を伝達しない限り、アプリの他の部分には見えません。その結果、コードのセクションを見て、そのセクション内のインスタンスへの変更は、接線方向に関連する関数の呼び出しからは見えないように行われるのではなく、明示的に行われることになります。
Objective-C の相互運用性が必要なときにはクラスを使用
データを処理する必要がある Objective-C API を使用する場合、または Objective-C フレームワークで定義された既存のクラス階層にデータモデルを合わせる必要がある場合は、クラスとクラス継承を使用してデータをモデル化する必要があります。たとえば、多くの Objective-C フレームワークでは、サブクラス化が期待されるクラスが公開されています。
ID を管理する必要がある場合にはクラスを使用
Swift のクラスは参照型であるため、ID の概念が組み込まれています。つまり、2 つの異なるクラス・インスタンスがそれぞれの格納されたプロパティに対して同じ値を持つ場合、それらは ID 演算子 (===) によって異なると見なされます。また、アプリ全体でクラス・インスタンスを共有した場合、そのインスタンスに加えた変更は、そのインスタンスへの参照を保持するコードのすべての部分に表示されます。インスタンスにこの種の ID を持たせる必要がある場合は、クラスを使用してください。一般的なケースは、ファイルハンドル、ネットワーク接続、および CBCentralManager のような共有ハードウェア仲介者です。
たとえば、ローカルデータベース接続を表す型がある場合、そのデータベースへのアクセスを管理するコードは、アプリから見たデータベースの状態を完全に制御する必要があります。この場合はクラスを使用するのが適切ですが、アプリのどの部分が共有データベースオブジェクトにアクセスできるかを制限するようにしてください。
ID を慎重に扱って下さい。アプリ全体でクラス・インスタンスを広く共有すると、ロジックエラーが発生しやすくなります。頻繁に共有されるインスタンスを変更した場合の結果は予想できないかもしれないので、そのようなコードを正しく記述するのは面倒です。
ID を管理しない場合は構造体を使用
自分が管理できない ID を持つ実体に関する情報を含むデータをモデル化するときには、構造体を使用します。
たとえば、離れたデータベースを参照するアプリでは、インスタンスの ID は外部の実体によって完全に所有され、ID によって伝達されます。アプリのモデルの一貫性がサーバーに保存されている場合は、レコードを ID 付きの構造体としてモデル化できます。以下の例では、jsonResponse はサーバーからのコード化された PenPalRecord インスタンスを含みます。
struct PenPalRecord { let myID: Int var myNickname: String var recommendedPenPalID: Int } var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
PenPalRecord のようなモデル型へのローカルな変更は役に立ちます。たとえば、アプリはユーザからのフィードバックに応じて複数の異なるペンパルを推奨することがあります。PenPalRecord 構造体は基になるデータベースレコードの ID を制御しないため、ローカルの PenPalRecord インスタンスに加えられた変更が誤ってデータベース内の値を変更する危険性はありません。
アプリの別の部分が myNickname を変更してサーバーに変更要求を送信しても、最後に拒否されたペンパルの推奨が誤って変更に反映されることはありません。myID プロパティは定数として宣言されているので、ローカルに変更することはできません。その結果、データベースへの要求が間違って誤ったレコードを変更することはありません。
継承と共有動作をモデル化するには構造体とプロトコルを使用
構造体とクラスはどちらも一種の継承をサポートします。構造体とプロトコルはプロトコルしか採用できません。それらはクラスから継承することはできません。ただし、クラス継承を使用して構築できる継承階層の種類は、プロトコル継承と構造体を使用してモデル化することもできます。
あなたが最初から継承関係を構築しているなら、プロトコル継承が望ましいでしょう。クラス継承は他のクラスとのみ互換性がありますが、プロトコルはクラス、構造体、および列挙型が継承に参加することを許可します。データのモデル化方法を選択するときは、最初にプロトコル継承を使用してデータ型の階層を構築してから、それらのプロトコルを構造体に採用してください。
以下も見よ
データのモデル化
Swift プロトコルに準拠していることを確認して、カスタム型を使いやすくします。
トップへ
トップへ
トップへ
トップへ