【継承とは】Swiftを使った挫折しないiOSアプリ開発入門 #3


はじめに

大学生向けに勉強会を行ったものを記事化したものです。

対象

今回のレベル:2.0

第2回までに作成したアプリの構造を紹介するとともに、さらにカスタマイズをしていきたいと思います。その中でプログラミングにおける継承とオーバーライド、 Storyboard の使い方を学ぶことができます。
※「クラス」や「関数・メソッド」といった最低限の内容に関しては参考書やWebページで学ぶことを想定しています

作るアプリ


GitHub(直ダウンロード)

前回に引き続き、こちらのアプリを開発しながら勉強していきます!

開発

たった2行書くだけでカメラアプリが作成できましたが、プログラミングの世界はここまで甘くありません 笑。しっかりとカラクリがあります。そのカラクリを少し推理してみてください!

実は、プログラムを書いていた場所の近くにカラクリのヒントがしっかりと書かれていました。 class MainViewController: BaseViewController { と書かれた部分です。この一行は MainViewController クラスが BaseViewController クラスを継承している ことを示しています。では、プログラミングにおける継承とはどのようなものなのでしょうか。

上記画像の中にも詳しい説明を引用していますが、言い換えるならば 引き継ぎ といえるでしょう。今回はカラクリを隠蔽するために使用したという理由もありますが、通常は何度も使用する共通処理などをまとめたクラスを継承して使います。
つまり、コードを書き始めた MainViewController はカメラアプリとしての機能をたくさん引き継いでいたということです。その 引き継がれたプログラムを私達が呼び出していただけ だったんです!

では、継承元である BaseViewController を見てみましょう! command キーを押しながらクラス名をクリックしてみてください。最新版の Xcode では control を同時に押すことで、簡単に移動することができます。もちろん、左端のファイル一覧から探しても構いません。
各メソッドの役割を上記画像に記載しています。これらの便利な機能が継承先でも使えちゃうのです!

先程の説明画像に override という言葉が出てきていました。今回も説明の一部を引用したものを上記画像に記載しています。言い換えるならば 上書き といえるでしょう。
実は、カラクリを作成する都合上、ボタンが押されたら呼ばれる onClickButton メソッドを UIViewController に追加していました。これを BaseViewControlleroverride して使っているのです。
記述方法としては、 override と書いてから上書きするメソッドと同じメソッド名・引数でメソッドを再定義します。このように再定義することで上書き元の処理ではなく、再定義した処理が実行されるようになります。

カラクリとして仕込んでいたプログラムを含む、今回使用しているプロジェクト内の関係を図にまとめてみました。 拡張 ですが、そのままの理由で、既存のプログラムを拡張して処理を追加しているということです。
この数スライドの間に用語が多く登場しましたが、私達がプログラムを書いていたクラスの継承元に便利な処理がすでに書かれていたということがなんとなくわかれば、次に進んでみましょう!
※カラクリを隠すことを優先した設計になっていることにご注意ください

さて、お待ちかねのプログラミングを実際に行っていきましょう!前回に引き続き工夫を施していきましょう。
BaseViewController の内容を見て気がついた人もいるかと思いますが、カメラを起動するボタンが配置された画面の背景画像を簡単に変更できる機能が実装されているので、使ってみましょう!
※以前の講義で説明した箇所に関しては詳しく説明しない箇所があります

上記画像中に手順が書かれています。注意する点としては、左側のファイル一覧で見た時に、 上に表示されるほど階層的には下にあることを示している ということです。最も手前にパーツを置きたいと思ったら、左側のファイル一覧で他のパーツよりも下に配置すればいいですね!
制約の付け方はわかりますか?前回は近くにある左右のパーツに対して制約をつけましたが、今回は同じ方法で上下にも制約をつけます。

ボタンのときと同じように、先程配置した UIImageView をプログラム側とリンクさせましょう。
次に、viewDidLoad メソッド内で setBKImage メソッドを呼んで、引数としてリンクさせた UIImageView を指定してください。
一旦実行してみましょう!カメラ起動ボタンがある画面の背景に画像が表示されるようになったと思います。もしボタンが見えなくなったようであれば、パーツの階層構造を見直してみてください。

ここで、アプリ内に好きな画像を取り込んで、プログラム側から使えるようにする方法を説明します。

この順番で説明していきます。

今回は画像管理に assets file と言うものを使います。拡張子が .xcassets となっているファイルを選択してください。

次に、左下のプラスマークから New Image Set を選択します。すると左側の一覧部分に新しい領域が追加されたと思います。好きな名前を付けて管理しましょう。この名前は、プログラム側から画像を呼び出す場合に必要になります。
名前をつけた箇所を選択すると、右側に画像の設定領域が表示されるので ドラッグ&ドロップで画像を取り込み ましょう。ここで アプリの実行環境の画面サイズに合わせて画像を用意 することができますが、今回は一番左に画像を設定しましょう。

次の工夫は今回のメインです!合成キャラクターを好きなものに変更し、カメラを起動するボタンを変えるだけで複数のキャラクターと写真撮影ができるようにしてみましょう。

前回までに行っている箇所もありますが、一通り振り返るとともに、作業手順を上記画像に示します。
まずは、 Storyboard を選択した状態でボタンを横一列に 3つ配置 します。ちなみに、制約の練習を解説するにあたり、横一列にしました。そして、全てのボタンを プログラム側にリンク させます。

3つのボタンに対して customSetting メソッドを呼んであげると上記画像のようになると思います。よくわからない人は、とりあえず真似してみてください!
一旦ここで実行してみてください。どのボタンを押しても同じキャラクターとしか写真撮影できませんね…

まずは、ボタンが押された時に呼ばれる onClickButton メソッドで、どのボタンが押されたのかを判断できるようにしましょう!ということで、各ボタンの tag にそれぞれ異なる番号を代入してください。これは、ボタンに名札を付けている感じです。

次に、 MainViewControlleronClickButton メソッドを override して ボタンの種類を判別する処理を書きます。判別には switch を利用します。詳しい使い方は次のスライドで説明しますが、一度処理について説明します。
sender に押されたボタン(のポインタ)が渡されるので、 sender.tag を見てボタンを判別していきます。 case 1: と書くことで tag が1だった時の処理を書き始めることができます。他の判別数字も同様の方法で記述できます。

上記画像を見るとわかりますが、カメラを起動する処理が1行ではありません…(前回まで1行だったのに)。なぜなら、キャラクター画像を設定する処理を記述する必要が出てきたからです。このように、 便利であっても柔軟性がなければ使いにくい ものになってしまいます。(今回は勉強会のために便利さを追求しました)

キャラクター画像の設定と画面遷移は以下のように記述できます。画像の読み込み方法は、少し前に説明しましたね!

case 1:
  let vc = CameraViewController()
  vc.setCharaImage("01") // 自分で取り込んだキャラクター画像の名前
  self.present(vc, animated: true, completion: nil) // カメラ画面に移動

さて、先程から switch と名前が出ていましたが、 Apple は上記のような説明を書いてくれています。 判別を行って別々の処理を行いたい 時に使います。使い方は以下のとおりです。

switch number {
case 1:
  // number が1だった時の処理
case 2:
  // number が2だった時の処理
case 3:
  // number が3だった時の処理
default:
  // どれにも該当しなかった時の処理
}

すでに C言語を勉強したことがある人向けに説明すると、 Swift では 各 case 毎に return される ので、下の case も処理されてしまうようなことはありません。C言語のような処理を実現する場合は if を利用するといいかもしれません。

onClickButton メソッドに対して、ここまで説明したことを実装すると上記画像のようになります。実行してボタン毎に自分で設定したキャラクターが表示され、合成された写真が撮影できれば成功です!
さて、少し余裕がある人や、もっと勉強したい人は以下の問題に挑戦してみましょう!

  • override で上書きではなく、処理の追加を実現するには?
  • onClickButton メソッド内の処理の冗長を解消するには?

こちらが回答例になります。プログラムなので、これ以外の回答例も考えられます。
override したメソッドで override 元の処理を行うには super を付けて同じメソッドを呼びます。この後に追加したい処理を記述することで「処理の追加」が実現できます。
冗長、つまり同じ処理ばかり だから、変化があるところだけを switch で処理するようにして、共通部分を1箇所にまとめると 書きやすく・読みやすく なりますね!

次回は、 Swift というプログラミング言語について 詳しく見ていくとともに、 YouTube アプリを自作 しながら学習を進めていきます!

最後まで見ていただき、ありがとうございます。

Swiftを使った挫折しないiOSアプリ開発入門シリーズ

以後、記事化中…