見出し画像

Lesson 4.1 Protocols

プロトコルは、物事がどのように行われるかを定義する一連のルールまたは手順です。コンピュータは、HTTP(ハイパーテキスト転送プロトコル)やTCP/IP(伝送制御プロトコル/インターネットプロトコル)などのプロトコルを使用して相互に通信します。HTTPは、2台のコンピュータ間でWebサイトデータがどのように通信されるかを定義する標準です。TCP/IPは、コンピュータが相互にデータを見つけて送信する方法を定義する通信規格です。

プログラミングでは、プロトコルは、タスクを完了するためにオブジェクトが持つ必要があるプロパティまたはメソッドを定義します。たとえば、Equatableプロトコルは、2つのインスタンスが互いに等しいかどうかを確認するために、型が==メソッドを定義する必要があると述べています。

このレッスンでは、プロトコルとは何か、いつ使用するか、独自のプロトコルを書く方法を学びます。オブジェクトが相互に通信できるようにするパターンである委任について学びます。また、複数のタイプで共有機能を提供するためにプロトコルを拡張する方法も学びます。

あなたが学ぶこと

プロトコルとは何か、なぜ使用されるのか

Swiftプロトコルについて学び、採用する方法

カスタムタイプのインスタンスが互いに等しい、大きい、または小さいかどうかを確認する方法

カスタムオブジェクトに関するカスタム情報をコンソールに印刷する方法

Vocabulary
adopt
Codable
Comparable
CustomStringConvertible
Equatable
implementation
protocol
read-only
read/write

p.531 
プロトコルは、特定のタスクまたは機能に適したメソッド、プロパティ、およびその他の要件の青写真を定義します。その後、プロトコルは別のタイプで採用することができ、これらの要件の実際の実装を提供します。プロトコルの要件を満たすすべてのタイプは、そのプロトコルに準拠しています。

Swift標準ライブラリは、アプリを構築する際に使用する多くのプロトコルを定義します。次のセクションでは、カスタムオブジェクトをコンソールに印刷する方法を制御できるCustomStringConvertible、同じタイプのインスタンスが互いにどのように等しいかを定義できるEquatable、同じタイプのインスタンスのソート方法を定義できるComparable、およびアプリの起動の間に保存できるキーと値のペアとしてタイププロパティを簡単にエンコードできるCodableの3つを見ていきます。

Swiftでプロトコルを採用すると、そのプロトコルに必要なすべてのメソッドを実装することを約束します。コンパイラは、すべてが整っていることを確認し、何かが欠けている場合はプログラムを構築しません。

CustomStringConvertibleによる印刷情報

Print() 関数を使用してオブジェクトがコンソールにどのように出力されるかを考慮することで、プロトコルの役割を理解し始めることができます。すでに学習したように、変数で print() 関数を実行すると、オブジェクトのテキスト表現がコンソールに書き込まれます。予測可能な結果で、文字列値、Int値、およびブール値を印刷できます。

p.532 
しかし、靴のクラスを定義したらどうなりますか?

ご覧のとおり、この印刷ステートメントはまったく役に立ちません。Swiftは、この種の状況に対処するためにCustomStringConvertibleと呼ばれるプロトコルを定義します。CustomStringConvertibleには、インスタンスの文字列表現を返す1つの必須の計算プロパティ、説明があります。プロトコルを採用すると、カスタム型が印刷可能な文字列値としてどのように表現されるかを正確に制御できます。

まず、コロンと採用するプロトコルの名前を追加してプロトコルを採用します。

p.533 
次に、必要な関数または変数を追加してプロトコルに準拠します。この例では、description computedプロパティを追加します。この手順を完了しないと、コンパイラにプロトコルに準拠していないというエラーが表示されます。

文字列レッスンでは、文字列補間を使用して定数または変数を文字列値に織り交ぜる方法を学びました。次のコードのdescriptionプロパティは、文字列補間を使用して、Shoeインスタンスの各プロパティを含むStringを作成します。

p.534 
コードは、各オブジェクトの初期化子のように見えるものを出力することに注意してください。これは、オブジェクトの各プロパティを使い慣れた簡潔な形式で表示できるため、一般的な方法です。ただし、必要なものは何でも印刷できます。

p.535 
情報を等しい情報と比較する

あなたのチームがあなたの会社のために従業員ディレクトリアプリを構築していると想像してみてください。あなたは、すべての従業員、役職、電話番号を表すデータモデルを構築することを任されています。

アプリの構築中に、従業員が自分の情報を編集し、他の人が編集できないようにする機能を構築するよう求められます。これを実現するには、ユーザーが自分の詳細画面に移動したときに編集ボタンを表示します。

しかし、それが適切な従業員であることを確認するにはどうすればよいですか?現在の従業員が従業員の詳細画面に移動するたびに、その従業員と情報が表示される従業員を比較する必要があります。

現在のユーザーに一致するEmployeeインスタンスを返す変数Session.currentEmployeeを使用して、現在の従業員にアクセスできるとします。従業員詳細画面の表示を担当するビューコントローラーには、従業員のプロパティがあります。アプリが新しい従業員詳細画面を読み込むと、Session.currentEmployeeと従業員が等しいかどうかを確認する必要があります。もしそうなら、編集ボタンを有効にします。そうでない場合は、ボタンを非表示にします。

次のようなものを書くことを検討してください。

p.536 
上記のコードは良い考えです。==演算子は、2つの値が互いに等しいかどうかをチェックします。しかし、従業員はカスタムタイプであるため、平等のために2つのインスタンスを比較する方法をSwiftに正確に伝える必要があります。これを行うには、Equatableプロトコルを採用します。

Equatableプロトコルでは、カスタムタイプの==演算子の実装を提供する必要があります。Lhs(左側)とrhs(右側)のパラメータを受け取り、2つの値が等しいかどうかを示すブール値を返す静的==関数を追加します。

従業員2人しかいない上記の例を考えてみましょう。2人の従業員が平等であるかどうかをどのように判断しますか?firstNameとlastNameの両方の値が両方の従業員で同じである場合、次のコードはtrueを返します。

p.537 
それは平等チェックを実施するのに悪いスタートではなかった。しかし、それはすぐに故障します。同じ名前の2人の異なる従業員を考えてみましょう。

コードがtrueを返すと、ディレクトリ内のお互いの情報を編集できます。2つの従業員インスタンスが等しいかどうかを確認するために、より良いチェックを設計するにはどうすればよいですか?

==メソッドを更新して、各プロパティを確認できます。

名、姓、役職、電話番号を比較すると、より信頼性の高い結果が得られます。プログラマーとして成長するにつれて、これらのタイプのエッジケースを認識し始め、コードでそれらを説明する方法を学びます。

比較可能な情報のソート

次に、姓でアルファベット順にソートされたすべての従業員のリストを表示することを任されていると想像してみてください。マネージャーは5人の従業員のサンプルリストを提供するので、リストを正しい順序で並べ替えるコードを書く実験をすることができます。

以下から始めます。

p.539 
上記のリストは特定の順序ではないことに注意してください。

Swiftは、<、<=、>、または>=演算子を使用してオブジェクトをソートする方法を定義できるComparableと呼ばれるプロトコルを提供します。

Comparableには2つの要件があります。型がEquatableプロトコルを採用している必要があり、開発者は<演算子を実装する必要があります。これは、左側の値が右側の値より小さいかどうかのブール値を返します。

この場合、従業員を姓でアルファベット順に並べ替えます。左側の値の姓の最初の文字が右側の値の姓の最初の文字よりも小さい場合は、<関数を実装してtrueを返すことができます。

次に、sorted(by:)関数を使用して、姓でソートされた従業員の配列を返すことができます。

p.540 
スウィフトは賢い。EquatableプロトコルとComparableプロトコルで定義した==演算子と<演算子の両方を使用して、<=、>、および>=演算子の機能も提供できます。

次の例では、ソートされたパラメータを<から>に変更し、ソートの順序を昇順から降順に反転させます。

p.541 
Codableによるオブジェクトのエンコードとデコード

多くのアプリは、ユーザーが次回アプリを開いたときにデータが存在するように、ユーザーの入力を保存します。ユーザーデータを保存するには、メモリに生息する値は、ファイルに書き込むことができるデータの形式にエンコードする必要があります。Codableプロトコルは、エンコーダまたはデコーダオブジェクトで使用できるオブジェクトのプロパティ名と値からキーと値のペアを作成することで、これをほぼ簡単にします。

標準ライブラリから使用するほとんどのSwiftタイプは、すでにCodableに準拠しています。カスタムタイプのプロパティがすべてCodableに準拠している場合は、型宣言にCodableを追加するだけです。

p.542 
これにより、エンコーダまたはデコーダオブジェクトは、タイプが特定のデータ形式との間でオブジェクトをエンコードまたはデコードするために必要なすべての情報を持っていることを知ることができます。

JSONEncoderを例に挙げてみましょう。JSONデータ形式は、本質的に情報を表すキーと値のペアのリストであり、Webサービスで作業するときによく使用されます。JSONEncoderは、Codableに準拠したオブジェクトをJSONに変換し、データとして簡単にエンコードしたり、キーと値のペアのリストを示す文字列として表示したりできます。

JSONEncoderのencode(_:)メソッドは、特定のタイプのエラーを返すことができる特別なタイプのSwift関数であるスロー関数と見なされます。やってみますか?関数がオプションの値を返すことを可能にする次のサンプルコードの構文。エラーがない場合、オプションは期待値を保持します。エラーがある場合、オプションはnilになります。トライについてもっと学びますか?別のレッスンの構文。

p.543 
コンソールに印刷された文字列を使用すると、オブジェクトがどのように異なる形式に変換されたかを垣間見ることができますが、それでも同じ情報を表します。Codableを使用すると、アプリの情報をさまざまな形式との間で簡単に変換できます。Codableプロトコルは、ユーザーデータを保存したり、Webサービスで作業したりする際の今後のレッスンに役立ちます。

プロトコルの作成

Swift 標準ライブラリで定義されている 4 つのプロトコルについて学習しましたが、独自のプロトコルを作成することもできます。

構造体、クラス、列挙を定義する方法を覚えていますか?プロトコルは非常によく似た方法で定義します。Protocolキーワードの後に使用する名前を使用し、一連の中括弧で要件を定義します。

プロパティを必要とするときは、プロパティが読み取り専用か読み取り/書き込みかを定義する必要があります。読み取り専用とは、変数を取得できるが、設定できないことを意味します。読み取り/書き込みは、値を取得して設定できることを意味します。プロパティが読み取り専用の場合は、計算されたプロパティを使用して実装できます。読み取り/書き込みの場合は、通常のプロパティである必要があります。

メソッドが必要な場合は、メソッドの名前、パラメータ、および戻り値の型を指定する必要があります。

次のコードは、fullNameプロパティと sayFullName() メソッドを必要とする FullyNamed プロトコルを定義します。型定義に似ていることがわかります。

このレッスンの前半のSwiftプロトコルと同様に、コロンを追加し、採用するプロトコルの名前を追加してプロトコルを採用します。

p.544 
コンパイラは、Person構造体がプロトコルを採用していることを認識しますが、構造体がまだ要件を満たしていないことも認識します。プロトコルを採用しているが、その要件を満たしていない場合、エラーに対処するまでコードをビルドまたは実行することはできません。

次のコードでプロトコルに準拠するのがいかに簡単かに注目してください。Person構造体は、フルネームの計算プロパティと、フルネームをコンソールに出力する sayFullName()関数で更新されます。

プロトコルを定義するための構文は、スーパークラスを宣言するための構文に似ていることに気付いたかもしれません。それは偶然ではありません。サブクラスの作成とプロトコルの定義は、共有されたプロパティと機能のセットを採用する2つの方法です。実際、クラスがスーパークラスから継承できるのと同じように、プロトコルを使用してデフォルトの実装を提供できます。プロトコルとデフォルトの実装については、このレッスンの後半で詳しく学習します。

p.545 
代表団

委任は、クラスまたは構造がその責任の一部を別のタイプのインスタンスに引き渡したり委任したりすることを可能にする設計パターンまたは一般的な慣行です。

現実世界の代表団について考えるのに役立ちます。タスクを委任する場合は、タスクまたは責任を他の人に手渡し、タスクが処理することを期待します。たとえば、マネージャーは従業員の1人にプレゼンテーションを委任することができ、マネージャーはプレゼンテーションを準備して配信することが期待されます。または、親は床に掃除機をかけることを子供の1人に委任し、その後雑用を処理します。

理解すべき重要なことは、タスクを委任している人と、実際にタスクを実行するのが誰の仕事であるかの2つの側面があるということです。

この関係はプログラミングでも同じです。タスクを実行する必要があるオブジェクトがあるかもしれませんが、それを実現するために実際にコードを実装するオブジェクトではないかもしれません。実装を他の型に委任する型は、通常、プロトコルを定義することによってそうします。プロトコルは委任される可能性のある責任を定義し、デリゲートは実際のタスクを実行するためにプロトコルを採用します。

デリゲートパターンは、UIKitやその他のiOSフレームワーク全体で広く使用されています。今後のレッスンでは、デリゲートパターンについて詳しく取り組もうと思います。

プロトコルは、このコースで使用するより高度なSwiftトピックの1つです。怖がらないでください。コースを進めながら、プロトコルを使用しながらプロトコルをマスターする方法を学びます。

この記事が気に入ったらサポートをしてみませんか?