Lesson 2.4 Classes, Inheritance

これで、データと機能を型にコンパイルする方法としての構造について学びました。多くのプログラミング言語は、同様の機能を実行するクラスと呼ばれる別の機能もサポートしています。特殊なケースでは、構造体の代わりにクラスを使用することができます(そして使用すべきです)。

クラスと構造は非常によく似ており、プログラムやアプリの構成要素として使用できます。このレッスンでは、クラスが構造体と異なる理由と、構造体の代わりにクラスを使用するタイミングを学びます。また、継承、スーパークラス、サブクラスについても学びます。

あなたが学ぶこと

・構造体とクラスの違い
・クラスの定義方法
・相続の概念と重要性
・別のクラスを継承するクラスの書き方
・クラスを使用してアプリケーション内の複雑な状態を管理する方法

Vocabulary
base class
class
inheritance
state
subclass
superclass

p.156 
クラスは構造と非常によく似ています。他の類似点の中でも、どちらも値を格納するプロパティを定義し、機能を提供するメソッドを定義し、初期状態を設定するための初期化子を定義できます。これらのことを行うための構文は、ほとんど常に同じです。

Classキーワードと一意の名前を使用してクラスを定義します。次に、適切な型アノテーションで定数または変数宣言をリストすることで、プロパティをクラスの一部として定義します。構造体と同様に、型の名前を大文字にし、プロパティの名前に小文字を使用するのがベストプラクティスです。

クラス定義に関数を追加することで、クラスに機能を追加できます。

構造に関する前のレッスンでほぼ同じ例を見ました。しかし、クラスは構造とどう違うのですか?

p.157 
遺産
構造とクラスの最大の違いは、クラスが階層的な関係を持つことができることです。どのクラスでも親子クラスを持つことができます。親クラスはスーパークラスと呼ばれ、子クラスはサブクラスと呼ばれます。

家族関係と同様に、サブクラスはスーパークラスからプロパティとメソッドを継承しますが、スーパークラスメソッドの実装を拡張または置き換えることができます。

以下のセクションでは、親クラスを持たないクラスである基本クラスを定義する方法、サブクラスの定義方法、および基本クラスのプロパティまたはメソッドをオーバーライドする方法について説明します。

基本クラスの定義
スーパークラスを継承しないクラスは、基本クラスと呼ばれます。これまでに見たクラスはすべて基本クラスです。

以下は、車両オブジェクトの基本クラスの例です。

p.158 
VehicleクラスにはcurrentSpeedというプロパティがあり、デフォルト値は0.0です。currentSpeedプロパティは、車両の人間が読める説明を返す計算された説明変数で使用されます。このクラスには、 makeNoise() というメソッドもあります。このメソッドは、実際にはベース車両インスタンスに対して何もしませんが、後でサブクラスによってカスタマイズされます。

車両クラスは、車、自転車、飛行機など、あらゆる種類の車両の特性や方法などの一般的な特性を定義します。それ自体はあまり役に立ちませんが、他のより具体的な型を定義しやすくなります。

サブクラスを作成する

サブクラス化とは、既存のクラスに新しいクラスを基にするという行為です。サブクラスは、スーパークラスからプロパティやメソッドなどの特性を継承し、より具体的に絞り込むことができます。サブクラスに新しいプロパティやメソッドを追加することもできます。

スーパークラスを継承する新しい型を定義するには、コロンで区切られたスーパークラス名の前に型名を記述します。

次の例では、車両のスーパークラスを持つ自転車と呼ばれるサブクラスを定義しています。

新しいBicycleクラスは、currentSpeedプロパティとdescriptionプロパティ、および makeNoise()メソッドなど、Vehicleのすべてのプロパティとメソッドを自動的に継承します。

p.159
継承されたプロパティとメソッドに加えて、Bicycleクラスは新しいブールプロパティハスバスケットを定義します。デフォルトでは、Bicycleの新しいインスタンスにはバスケットがありません。hasBasketプロパティは、作成後の特定のBicycleインスタンスに対してtrue、またはそのタイプのカスタムイニシャライザ内で設定できます。

予想通り、currentSpeedプロパティを更新することもできます。これはインスタンスの説明に影響します。

サブクラス自体はサブクラス化できます。たとえば、2人乗りのTandemBikeを表すクラスを作成できます。

タンデムは自転車からすべてのプロパティとメソッドを継承し、車両からすべてのプロパティとメソッドを継承します。Tandomサブクラスは、デフォルト値が0のcurrentNumberOfPassengersという新しいプロパティも追加します。

タンデムの新しいインスタンスを作成すると、継承されたすべてのプロパティとメソッドにアクセスできます。

p.160

メソッドとプロパティをオーバーライドする
サブクラス化の利点の1つは、各サブクラスがプロパティまたはメソッドの独自のカスタム実装を提供できることです。関数の新しい実装を書くなど、継承される特性をオーバーライドするには、新しい定義の前にoverrideキーワードを付けます。

次の例では、TrainがVicleから継承する makeNoise()メソッドをオーバーライドする新しいTrainクラスを定義しています。

また、ゲッター、または計算されたプロパティなどの値を返すコードブロックを提供することで、プロパティをオーバーライドすることもできます。次の例では、車両のサブクラスであるCarという新しいクラスを定義しています。新しいクラスには新しいギアプロパティがあり、デフォルトは1の値。Carクラスはまた、descriptionプロパティをオーバーライドして、現在のギアを含むカスタム説明を提供します。

p.161 
新しい実装は、super.descriptionを呼び出すことでスーパークラスから説明にアクセスすることに注意してください。新しい実装は、ギアに関する情報を提供するために、説明の最後に余分なテキストを追加します。

初期化子をオーバーライドする

nameプロパティを持つPersonクラスがあるとします。初期化子は、指定されたパラメータに名前を設定します。

p.162 
さて、Personのサブクラスである学生を作りたいと想像してみてください。各学生には、追加のプロパティ、お気に入りサブジェクトが含まれています。

このコードをコンパイルしようとすると、favort favoriteSubjectプロパティを初期値に設定する初期化子を提供していないため、学生は失敗します。Personスーパークラスはすでにnameプロパティを初期化する作業を行っているため、Student初期化子はsuper.init()を使用してスーパークラスの初期化子を呼び出すことができます。サブクラス内に追加されたプロパティの値を指定した後、この初期化子を呼び出す必要があります。

スーパークラスの初期化子を呼び出すことで、学生クラスはPerson初期化子にすでに書かれた作業を複製する必要はありません。

参考文献

クラスの特別な特徴は、定数または変数に割り当てられた値を参照する機能です。クラスのインスタンスを作成すると、Swiftはそのインスタンスを保存するためにデバイスのメモリ内のリージョンを選択します。メモリ内のその領域にはアドレスがあります。そのインスタンスに割り当てられた定数または変数は、インスタンスを参照するアドレスを保存します。

したがって、定数または変数には値自体が含まれていないため、メモリ内の値を指します。

p163 
複数の変数にクラスを割り当てると、各変数はメモリ内の同じアドレスを参照または指します。したがって、変数の1つを更新すると、両方の変数が更新されます。

対照的に、構造体のインスタンスを作成するとき、その変数にリテラル値を割り当てることになります。別の構造変数に等しい変数を作成すると、その値がコピーされます。いずれかの変数に対して実行した操作は、変更された変数にのみ反映されます。

p164 
メンバーワイズイニシャライザー

クラスのインスタンスを作成するときは、すべてのプロパティ値を設定する必要があることを学びました。構造体とは異なり、Swiftはクラスのメンバーごとの初期化子を作成しません。ただし、開発者は、定義したクラスに対して独自のメンバーごとの初期化子を作成し、すべての初期値がオブジェクトのインスタンスごとに設定されるようにするのが一般的です。

クラス、それとも構造?

クラスと構造は非常に似ているため、いつクラスを使用するか、いつプログラムの構成要素に構造を使用するかを知るのは難しい場合があります。

原則として、クラスが提供する機能の1つが必要になるまで、新しい型を構造体として開始する必要があります。

クラスを使用するフレームワークで作業している場合、または複数の場所で型の同じインスタンスを参照する場合は、クラスから始めます。

クラスを使用するフレームワークの操作

多くの場合、FoundationやUIKitなどのフレームワークなど、書いていないリソースを操作します。このような状況では、基本クラスから始めて、

p.165 
独自の特定の機能を追加するためのサブクラス。たとえば、UIKitで作業していて、カスタムビューを作成する場合は、UIViewのサブクラスを作成します。

フレームワークを扱うとき、多くの場合、クラスインスタンスを渡すことが期待されます。多くのフレームワークには、特定のものがクラスであることを期待するメソッド呼び出しがあります。したがって、このような場合、常に構造体よりもクラスを使用することを選択します。

安定したアイデンティティ

オブジェクトの1つのインスタンスを複数の場所で使用したい場合がありますが、インスタンスをコピーするのは意味がありません。各クラスの定数または変数は同じデータを指すアドレスであるため、データは安定したアイデンティティを持っています。

テーブルビューの行を表すUITableViewCellサブクラスMessageCellを考えてみましょう。このセルは、電子メールメッセージに関する情報を表示するように設計されています。MessageCellの各インスタンスは、ご覧のとおり、コード内の多くの場所からアクセスされます。

テーブルビューがセルを表示する準備をしているときは、関数cellForRow(at: IndexPath)を呼び出して、リストの各位置に表示するセルを要求します。テーブルビューのすべてのセルは、この関数呼び出し中に初期化(およびメモリに入れられます)。

p.166 
ユーザーがテーブルビューのメッセージのリストをスクロールすると、プログラムが表示しようとしているセルを設定、更新、または変更できるメソッドが呼び出されます。この関数は、セルへの参照をパラメータとして渡します。

ここにはなじみのない構文があり、後で詳しく学びます。今のところ、テーブルビューに表示しようとしている各セルに対して関数が呼び出されるという事実に焦点を当てます。また、関数は、すでに存在するtableViewへの参照、すでに存在するが表示されようとしているセル、およびindexPathと呼ばれるものの3つのパラメータを渡すことに注意してください。

tableViewとcellは両方ともクラスであるため、パラメータはメモリ内のtableViewとセルへの参照です。セルパラメータを更新すると、表示しようとしているセルと同じセルであるcellForRow関数で初期化されたのと同じセルを更新します。

クラスが構造体とどのように異なるかを考えてみましょう。セルが構造体または値型の場合、パラメータは表示されようとしているセルの新しいコピーになります。したがって、セルを更新した場合、表示しようとしているセルではなくコピーを更新したため、変更は表示されません。

安定したアイデンティティの文脈で参照を理解するのに苦労していますか?大丈夫です。これらの概念を使用してプロジェクトを完了する必要がある場合、今後のレッスンで詳細を学びます。

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