こんにちは。
キャスレーコンサルティング TS(テクニカルサービス)部の瀧下です。
この度、私が担当しているプロジェクトで開発中のAndroidアプリを
iOSアプリ用に移行するために、未経験のSwift言語を扱うことになりました。
そのため、簡単にではありますが、
予習として基礎を抑えながら、Swiftのイベント通知を実装してみようと思います。
目次
1.はじめに
2.実行環境
3.実装
4.最後に
1.はじめに
通知と言っても、端末に表示されるプッシュ通知のような通知とは異なります。
イベントの発生箇所になるオブジェクトが、
ほかのオブジェクトのイベント発生を伝えることをイベント通知と言います。
イベントとは、UI要素のタップやプロパティの値の変更など、
アプリケーション内で発生するあらゆる事象のことです。
イベント通知が発生するケースとしては、
オブジェクトAがオブジェクトBに処理を依頼したり、
処理の開始や終了を伝えたりするケースが考えられます。
オブジェクト間のイベント通知は、以下3つの方法に大別されます。
- デリゲートパターン
- クロージャ
- オブザーバパターン
今回は、デリゲートパターンによるイベント通知を実装していきます。
デリゲートパターンは、処理を別のオブジェクトに代替させるパターンです。
デリゲート元のオブジェクトが別オブジェクトに対して、メッセージを送り、
デリゲート先のオブジェクトはメッセージを受けて、別オブジェクトの状態を変更したり、
結果をデリゲート元のオブジェクトに返したりします。
2.実行環境
残念なことに、私はMacを持っていないため、WindowsでSwiftの開発環境を構築しました。
Swiftのオープンソース化により、UbuntuでもSwiftが使えるようになったため、
Windows上でUbuntuを動かすことができる、「Bash on Ubuntu on Windows」を使い、
Swiftファイルを実行していきます。
Swiftファイルを実装するエディタは、Atomを使います。
Atomは、GitHubで開発された開発者向けに様々な機能を扱っているテキストエディタです。
- Windows10
- Bash on Ubuntu on Windows(16.04)
- Swift-4.0.2
- Atom
3.実装
3-1.プロトコルの定義
気温測定のデリゲートパターン通知を、実装していきます。
必要な処理は、プロトコルとして宣言されている必要があるので、
デリゲートする処理をプロトコルメソッドとして宣言します。
クラス専用のプロトコルを定義するには、以下のようになります。
protocol TemperatureDelegate : class { var place: String { get } func measurementStart(_ temperature: Temperature) func measurementEnd(_ temperature : Temperature) }
中身はプロパティを定義します。
序盤ですが、先にSwiftの変数、関数定義のポイントについてご紹介します。
●Swiftにおける変数定義のポイント
varで変数、funcはメソッドの定義です。
ちなみに変数定義時、Swiftは型推論型を採用しているので、
初期化で値を入れる場合は型を省略することも可能です。
var value = 1
型を定義してあげる場合は、このように定義します。
var value:Int = 1
個人的にJavaに慣れているので、型を定義してあげた方が親切とか思ったりします。
●Swiftにおける関数定義のポイント
続いてメソッドの定義に使用されるfuncですが、以下のように引数に “_ ” が付くのはなぜでしょう?
func method(value1: Int, _ value2: Int) { }
それは、以下のようにメソッド呼び出しの際に、ラベルを省略できるためです。
method(1, 2)
という事は、”_ “が付いていない場合は呼び出し時にラベルを指定してあげる事が必要です。
func method(value1: Int, value2: Int) { } method(1, value2: 2) // 2つ目以降の引数にはラベルが必要になる // 1つ目を必須にする方法もある
引数の省略する方法もあり、面白いです。
func method(intValue1: Int = 0, intValue2: Int = 1) { } method()
3-2.プロトコルに準拠したクラスの作成
次に、プロトコルに準拠したクラスを作成します。
class PlaceDelegate : TemperatureDelegate { var place: String { return "Shinagawa" } func measurementStart(_ temperature: Temperature) { print("Temperature Start") } func measurementEnd(_ temperature: Temperature) { print("Temperature end")} }
定義できたところで、実際にデリゲート元のクラスとメソッドを書いていきます。
3-3.デリゲート元の実装
start()メソッドの中で、delegateプロパティを通じてデリゲート先に気温を問い合わせます。
そして測定開始、測定終了のタイミングをデリゲート先に伝えています。
class Temperature { weak var delegate: TemperatureDelegate? func start() { print("This place is \(delegate?.place ?? "")") delegate?.measurementStart(self) print("Measuring") print("The temperature is \(degree) degrees") delegate?.measurementEnd(self) } }
●weakキーワードとは?
weakキーワードでプロパティを定義すると、弱参照となり、循環参照の解消に使われます。
循環参照は、インスタンス同士が強参照を持ち合う状態で、インスタンスが不要になっても、
そのメモリを確保したままになってしまうため、メモリリークなどのパフォーマンス低下となります。
デフォルトでプロパティを定義すると強参照となるため、
デリゲート元からデリゲート先への参照を弱参照として、循環参照を回避します。
3-4.呼び出し
参照の代入、及びメソッドの呼び出しをしていきます。
Swiftのクラスは参照型で、変数や定数への参照型の値の代入は、
インスタンスに対する参照の代入を意味するため、
複数の変数や定数で、1つの参照型のインスタンスを共有可能です。
let delegate = PlaceDelegate() let place = Temperature() place.delegate = delegate place.start()
letは、Swiftで以降変更不可能な定数の定義で使われます。
実装は、以下のようになりました。
SwiftファイルをUbuntuのコマンドから実行すると、以下の実行結果になりました。
【命名規則】
デリゲートパターンでは、デリゲート先にデリゲート元から呼び出されるメソッドを
実装する必要があります。
どのようなメソッドを実装する必要があるか?は、プロトコルとして宣言します。
4.最後に
デリゲートパターンは、以下のように非同期処理中に発生するイベントに応じて、
処理を実行することに有効です。
- 非同期処理を開始したタイミングで、プログレスバーを表示する
- 非同期処理が完了したタイミングで、プログレスバーを非表示する
- 非同期処理が失敗したタイミングで、エラーダイアログを表示する
今回は、Swiftの基礎的な学習として、記述させていただきました。
Swiftの形には触れることができたので、たくさん書いて使いこなしていきたいです。
Ubuntuでも動き方は一応見ることができるイベント通知について、ご紹介させていただきましたが、
基本Xcode以外は非推奨の為、できることが制限されるため、
MacのXcodeで暗号化ライブラリを使用した暗号化などを試してみたり、
実際にiOSアプリを作って、実機にインストールして動かしてみたいです。
Mac以外の開発環境でも、Swiftで充実して開発できる日が訪れることを願いたいと思います。
以上、最後までお読みいただきありがとうございました。