*

Xcode(Objective-C)のデリゲートとプロトコルの使い方[後編]

公開日: : 最終更新日:2014/08/28 Objective-C ,


スポンサードリンク



[前編]ではXcodeが既に用意しているデリゲートを利用した実装例について説明させていただきました。

より洗練されたアプリ開発を行いたい場合には、プロトコルの利用は必要不可欠であると思います。

[後編]では前編で説明を省略していたプロトコルの説明をした後、
新しくプトロコルを定義し、そのプロトコルに対応するデリゲートを実装するとの内容を説明させていただきます。

繰り返しになりますが、本エントリーは以下の様になります。

  1. Objective-Cのプロトコルとは
  2. プロトコル、デリゲート定義のサンプル実装

 

1 Objective-Cのプロトコルとは

プロトコル(protocol)との言葉自体は、「複数の者が対象となる事項を確実に実行するための手順等について定めたもの。」との意味です。
よくJavaのインターフェースと比べられますが、私が思う両者の違いは以下の様になります。

Javaのインターフェース

  • インスタンス変数が定義できる。
  • インターフェースで定義した全メソッドを、インターフェース実装クラスで実装しないといけない。

Objective-Cのプロトコル

  • メソッドしか定義できない。
  • プロトコルで定義された任意のメソッドを、プロトコルの実装クラスで実装することを必須・非必須の指定ができる。

Objective-Cの2つ目がイマイチ分かりにくいですね、日本語下手すぎ・・・
後ほどこの部分については詳細な説明をいたしますので、「ああそうなんだ」ぐらいで見逃してください。

Objective-Cのプロトコルの記載方法

プロトコルの定義例1

以下のコードは、PersonProtocolDelegateという名前のプロトコルを定義したものです。

1行目:<NSObject>はNSObjectを継承したプロトタイプであることを意味しています。
3行目:(NSString*)helloを定義しています。メソッドの定義方法も普通のメソッド定義と同様です。
ここで注目すべきポイントがあります。行が前後しますが、5行目の@requiredと8行目の@optionalです。
@requiredはそのプロトコルを実装するクラスが必ず実装しなければならないメソッドです。
@optionalははそのプロトコルを実装するクラスでの実装は任意(しても、しなくてもよい)となります。

ではこのhelloは?となると思います。@required、@optionalが未指定の場合は@optional相当と解釈されます。

6行目:(NSString*)thankYou:(NSString *)nameの定義をしています。@requiredなので実装クラスでの実装が必須となります。
9行目:- (NSString*)sayWhy定義をしています。@optionalなので実装クラスでの実装は任意となります。
だけです。

プロトコルの定義例2

定義例1では@requiredや@optional、及び未指定との設定がどこまで有効かの説明をしておりませんので、この部分を明確にするための例を以下に示します。

先ほどの例と基本は同じでメソッド定義が3つ追加されています。
hello2はhelloと同じで@optional相当
thankYou2はthankYouと同じで@required相当
sayWhy2はsayWhyと同じで@optionalとなります。
敢えて別の例を挙げて説明するまでも無かったかもしれません・・・

2 プロトコル、デリゲート定義のサンプル実装

本節では、ちょっとしたUIを保持したアプリの作成過程という形で、実際の実装方法を説明させていただきます。

ちょっとしたUIを保持したアプリの説明

起動時の画面は以下のようになっております。
関西人モードとの謎のラベルが付いたスイッチ、おしゃべりボタン、フラットデザインなので見えないですが画面上部にテキストビューがあります。
スクリーンショット 2014-03-31 16.20.57

この謎のスイッチでデリゲート先を切り替えて、おしゃべりボタンを押した時の動作を変えるとのアプリです。
動作を変えると言ってもテキストビューに表示される内容が変わるだけです。

動きはショボイですが、プロトコルのデリゲート先クラス(ノーマルクラス、関西人クラス)を作成し、謎のスイッチでデリゲート先クラスを切り替えるようになっています。

関西人モードの時のおしゃべりボタンタップ時の画面イメージ
スクリーンショット 2014-03-31 16.15.14

関西人モードじゃない時のおしゃべりボタンタップ時の画面イメージ
スクリーンショット 2014-03-31 16.17.10

以降では、このアプリを作成しながらプロトコルとデリゲート、及びそれらの利用方法の説明させていただきます。

プロジェクトの作成

作成するプロジェクトの「template」は「Single View Application」を指定してください。
「Product Name」はProtocolDelegateSample、「Company identifier」はcom.exampleを指定してください。

画面コンポーネントの配置とInterface Builderの接続

画面コンポーネントの配置

・テキストビューの配置
「Text View」を配置します。
スクリーンショット 2014-03-30 19.21.06

配置した時のサイズを変更し、以下の大きさぐらいにします。
スクリーンショット 2014-03-31 15.56.31

あとデフォルトで表示されているテキストが目障りなので消します。
以下の画像の赤枠部分の文字を削除すると消えます。
スクリーンショット 2014-03-31 15.57.53

・スイッチを配置
スクリーンショット 2014-03-30 19.34.38

・スイッチの右のラベルを配置と文言の修正
スクリーンショット 2014-03-30 19.42.25

文言の修正は以下の画像の赤枠部分で行えます。
スクリーンショット 2014-03-30 19.44.42

コンポーネントをダブルクリックすることで変更もできます。
以下の様に青くなった状態が編集できる状態です。
スクリーンショット 2014-03-30 19.46.44

ラベルのテキストは「関西人モード」となったのですが、画面がおかしいです。
スクリーンショット 2014-03-30 19.57.13

Xcodeのラベルは表示する文字列によって、自動的にサイズは変わりません。
ソースに1行書けば自動リサイズする方法はあります。そうしないとラベルに表示する文字列変更した時に、実装者がえーと、サイズはいくらになるから、このサイズを指定みたいなことやるのは非現実的です。

確か、どこかのエントリーで記載したような・・・
ありました。「Xcode5で画面コンポーネントを利用するための基本」ですね。
リサイズはsizeToFitメソッドですので、ラベルに対してsizeToFitを呼び出せばOKです。しかしまだアウトレット接続していないので、エディタで大きくしてください。こんな感じにお願いします。
スクリーンショット 2014-03-30 20.59.42

・ボタンを配置
スクリーンショット 2014-03-30 21.00.53

配置後にボタンのラベルを”おしゃべり”に変更します。
スクリーンショット 2014-03-30 21.05.34

Interface Builderの接続

まずはテキストビュー、スイッチ、ボタンをアウトレット接続します。

テキストビューを選択して「Control」ボタンを押しながらViewController.hにドロップします。
nameにはtextViewを指定してください。
スクリーンショット 2014-03-30 21.14.37

スイッチとボタンも同様にアウトレット接続してください。
nameにはkansaiSwitch、chatButtonを指定してください。

アウトレット接続完了後のViewController.hは以下の様になりました。

ボタンはタップのイベントが必要ですのでタップイベントを接続します。
ボタンを選択して「Control」ボタンを押しながらViewController.hにドロップします。
表示される画面で以下の通り変更してください。
スクリーンショット 2014-03-30 21.29.22

実装するファイルの説明

実装する物は以下の様になります。
「前編での対応ファイルorクラス」とは「Xcode(Objective-C)でデリゲートを使ってみる。[前編]」でUIAlertViewDelegateを例として用いた際の対応するクラスを記載しています。

ファイル名 説明 前編での対応クラス
PersonProtocolDelegate.h PersonProtocolDelegateプロトコルを定義するファイル UIAlertViewDelegate
Person.h、Person.m PersonProtocolDelegateプロトコルを定義するファイル UIAlertView
NormalPersonDelegateImpl.h、NormalPersonDelegateImpl.m PersonProtocolDelegateプロトコルのデリゲート先(一般人) ViewController
KansaiPersonDelegateImpl.h、KansaiPersonDelegateImpl.m PersonProtocolDelegateプロトコルのデリゲート先(関西人) ViewController

実装内容のシーケンス図

これから実装する処理の簡易なシーケンス図を以下に示します。

少し分かりにくいですが、ViewController.hのプロパティpersonのプロパティdelegateがPersonProtocolDelegateの実装(デリゲート先)クラスの格納先となります。
スクリーンショット 2014-03-31 12.53.03

なお上図は、PersonProtocolDelegateプロトコルのデリゲート先がNormalPersonDelegateImplの時の図となります。
デリゲート先がKansaiPersonDelegateImplの場合は、PersonのプロパティdelegatにKansaiPersonDelegateImplをセットするだけの違いです。

プロトコルとデリゲートの実装

画面周りは整ったので、いよいよ本題の部分の実装です。

プロトコルの作成

PersonProtocolDelegateという名前のプロトコルを作成します。

プロジェクトナビゲーターで右クリックし、「File New …」をクリックします。
スクリーンショット 2014-03-30 21.45.20

表示された画面で、「Objective-C Protocol」を選択し「Next」ボタンをクリックします。
スクリーンショット 2014-03-30 21.45.35

protocolにPersonProtocolDelegateと入力して「Next」ボタンをクリックします。
スクリーンショット 2014-03-30 21.49.34

最後に作成場所を選択する画面が表示されますので、以下の画面と同じ状態にして「Create」ボタンをクリックしてください。
PersonProtocolDelegate.hが作成されました。
スクリーンショット 2014-03-30 21.53.42

中身は以下の通りです。

このプロトコル定義を前記の「Objective-Cのプロトコルの記載方法」のプロトコルの定義例1に変更します。
各メソッド定義の意図はメソッド名そのままです。
hello:あいさつの言葉を返す。
thankYou:nameに対するお礼の言葉を返す。
sayWhy:なぜ?との不思議なときに言う言葉を返す。メソッド名ちょっとセンス悪いですね・・・

画面にあるスイッチで、このプロトコルを実装する2つのクラス(デリゲート先)を切り替えて
ボタンをタップした時にテキストビューに表示される文字列が変わるようにします。

もちろん、そんなのプロトコル、デリゲートを使わなくてもできますが、サンプル実装なので、その点はご了承ください。

プロトコルをプロパティとして保持するクラスの作成

プロトコルの実装(デリゲート先)クラスを保持するクラスを作成します。「実装内容のシーケンス図」を見ていただければお分かりだと思いますが、Personという名前のクラスを新規追加してください。
スクリーンショット 2014-03-31 12.33.34

スクリーンショット 2014-03-31 12.45.22

スクリーンショット 2014-03-31 12.46.34

Person.hの内容を以下の様に変更します。
ポイントはプロパティのdelgateです。

Person.mの内容を以下の様に変更します。
処理内容なコード内部のコメントを参照ください。

プロトコルの実装(デリゲート先)クラスの作成

スイッチがON、OFFに対応するプロトコルの実装ファイルを作成します。
ONの場合はNormalPersonDelegateImplクラス
OFFの場合はKansaiPersonDelegateImplクラス
とします。

結構、どんな名前にするか悩んだのですが、PersonDelegateの実装クラスなので、
Javaのインタフェースに対する実装クラスによくあるパターンの”Impl”で終わり、
先頭は、実装クラスの振る舞いが連想できる文字列の”Normal”と”Kansai”としました。

クラスの作成時の画面はもう貼付けませんが、NormalPersonDelegateImplとKansaiPersonDelegateImplを作成してください。

NormalPersonDelegateImpl.hの内容を以下の様に変更します。

NormalPersonDelegateImpl.mの内容を以下の様に変更します。
ポイントはhelloとthankYouの2メソッドを実装しsayWhyは実装していないこです。

KansaiPersonDelegateImpl.hの内容を以下の様に変更します。

KansaiPersonDelegateImpl.mの内容を以下の様に変更します。
こちらは三メソッド全て実装しています。

ViewControllerのdoChatの実装

最後に「おしゃべりボタン」がタップされた時の処理を実装するのですが、肝心のPersonProtocolDelegateのデリゲート先を切り替えるためのPersonクラスがViewController.hに定義できておりませんので定義します。

ViewController.hを以下の様に変更しました。
@property (strong) Person *person;を追加しています。

いよいよViewControllerのdoChatの実装です。
ViewController.mを以下の様に変更しました。
ポイントは_kansaiSwitch.onの値で分岐し、personのdelgateにKansaiPersonDelegateImplかNormalPersonDelegateImplのインスタンンスをセットするところです。

これで「実装内容のシーケンス図」の内容+KansaiPersonDelegateImplがデリゲート先の処理が完成したように見えます。
見えますと書いた意味ですが、実は意図的に問題があるようにしています。

実行して、スイッチをOFFにしてチャットボタンをクリックすると異常終了します。
スイッチがONの場合は正常に動作します。
スクリーンショット 2014-03-31 15.20.52

本来ならば様々な方法でデバッグし、問題点を明らかにすべきですが、エントリー自体が長くなってきているANDデバッグに関する別エントリーを作成することを考えておりますので、問題点を修正します。

問題点の修正

異常終了する理由は、Person.mのdoChatメソッドの内容に不備があるからです。
NormalPersonDelegateImpl.mでsayWhyメソッドを実装していないことが考慮されていないためです。

じゃあNormalPersonDelegateImplでsayWhyを実装すればいいのでは?、と思ったらダメです。
sayWhyはPersonProtocolDelegateで@optionalと指定されており、実装は任意であるためです。
実装が任意と言う事は、実装されていない場合はsayWhyを呼び出さないとの制御が必要になります。

同じ事がhelloメソッドにも言えるのですが、今回はたまたま2つの実装クラスで実装されていただけで、ここで異常終了が発生しなかったのは運が良かっただけです。

この点を考慮してPerson.mのdoChatメソッドを変更しました。
変更後のPerson.mは以下のようになりました。
delgate自体のチェックも追加しています。

修正後の実行結果は予期した通りになりました。

関西人モードのチェックがONでボタンがタップされた場合
スクリーンショット 2014-03-31 16.15.14

関西人モードのチェックがOFFでボタンがタップされた場合
スクリーンショット 2014-03-31 16.17.10

あ、さんさんになってる・・・

Xcode(Objective-C)のデリゲートの使い方[後編]は以上です。

結局、デリゲートの各メソッドを呼び出して文字列に連結していくだけなのでイマイチな例ですが
「Xcode(Objective-C)のデリゲートの使い方[前編]」のUIAlertViewDelegateと合わせて考えていただければと思います。

本エントリーで作成したプロジェクトをアップして置きます。
ProtocolDelegateSample


スポンサードリンク

Googleアドセンス

Googleアドセンス




関連記事

iOS(Xcode6とObjective-C)におけるマルチスレッド(非同期)処理の実装方法その2[GCD(Grand Central Dispatch)の利用]

本エントリーではGCD(Grand Central Dispatch)を利用したiOSのマルチスレッ

記事を読む

Objective-Cでコールバック処理を@Selectorで実現する方法

最近はSwiftばっかり読み書きしていますが、既存のライブラリをカスタマイズして使うことも多いので

記事を読む

Xcode5でSchemeを利用する。[後編]

「Xcode5でSchemeを利用する。」の続きの「Xcode5でSchemeを利用する。[後編]」

記事を読む

Xcode5でSchemeを利用する。[前編]

Xcode5の「Scheme」の作成方法や使い方のエントリーとなります。 思った以上に内容が多くな

記事を読む

Xcode5のナビゲーションエリア[プロジェクト、シンボル、検索]の使い方

Objective-Cでコーディングを行うための統合開発環境のXcodeの利用方法のエントリーです。

記事を読む

Xcode5で画面にツールバーを配置して利用する。

「ナビゲーションバー」と同様に「ツールバー」もナビゲーションコントローラ(UINavigationC

記事を読む

Xcode5で画面コンポーネント(UIコンポーネント)配置して利用するための基本

iOSアプリケーションは当然ですが、画面がありますよね。 言わずもがなですが、iOS向けのアプ

記事を読む

Xcode5の「Auto Layout」機能の使い方[簡単な画面レイアウトを構成してみる。]

「基礎知識と制約(Align:アライメント)の設定方法」 で「Auto Layout」機能の利

記事を読む

Xcode6からはProjectName-Prefix.pchは自動的に生成されませんが、それでもpchファイルを利用したい時の利用方法

小ネタですが、Xcode6からはProjectName-Prefix.pchは自動的に生成されなくな

記事を読む

Xcode(Objective-C)のデリゲートとプロトコルの使い方[前編]

Xcode(Xcode5でも同様)でアプリ開発をしていて、少し複雑な事をしようとするとデリゲートと言

記事を読む

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

動画で英語を学習できるiOSの無料アプリCapTubeをリリースいたしました。

個人では初となるiOSアプリをリリースいたしました。 何度もリジ

no image
Ruby on rails4系でBootstrapを利用するためのtips

MacでRuby on rails4系のBootstrapを利用しよう

no image
Java、Eclipse、JUnit関連のエントリーの移行のお知らせ

Java、Eclipse、JUnit関連のエントリーは http:/

iOS8開発者向けお勧め本紹介[詳細! Swift iPhoneアプリ開発 入門ノート Swift 1.1+Xcode 6.1+iOS 8.1対応]

iOS7開発者向けお勧め本紹介を以前に紹介させていただきまいたが、今回

Swift入門(Xcode6のXCTestフレームワークで学ぶ) 第二回「関数(メソッド)とクロージャーの利用方法」

前回はSwiftの概要をザックリと説明させていただきました。 今

→もっと見る

Optimization WordPress Plugins & Solutions by W3 EDGE
PAGE TOP ↑