第6章 デザインパターン | ||
ホーム | メール | |
目次 | < 前ページ 次ページ > |
「デリゲート」の節では、入力のたびにModelオブジェクトに格納されている文字列がコンソールウィンドウに表示されました。しかしあれでは少し忙し過ぎましたね :-) 今度はModelオブジェクトの内容をコンソールに表示したいときにはボタンを押すようにします。じょじょにアプリケーションらしく変わっていきます。なおこのボタンはのちほど大事な役割を果たすことになります。
ターゲットアクションはObjective-Cの中ではデリゲートよりも代表的なデザインパターンと言えるでしょう。しかしサンプリアプリケーショMyClipの作成過程と合わせるためにデリゲートの次に紹介することにいたしました。ここまでに登場してきたデザインパターン(設計様式)を登場順に記述すると次のようになります。
しかしこれを代表的な順番に並びかえると次のようになります。
この節でも、まずターゲットアクションの簡単な説明をいたします。次に実際の作業をしていただき。そしてそのあとでもう一度詳しい説明をしたいと思います。
ターゲットアクションとデリゲートはともにメソッドの実行をほかのオブジェクトに依頼しているという点では同じです。3章のオブジェクトの節でも説明したとおりにメソッドの実行を外注先に出しているわけです。しかしターゲットアクションとデリゲートで大きく違う点もあります。デリゲートではdelegateというインスタン変数にメソッドの実行を依頼するオブジェクトを接続しました。
一方ターゲットアクションでもtargetというインスタン変数にメソッドの実行を依頼するオブジェクトを接続しますが、さらにもうひとつactionというインスタン変数に実行を依頼するメソッドのセレクターを登録します。この点が一番大きな違いと言えます。そしてもうひとつ、ターゲットアクションはNSControllerクラスを継承したクラスだけが持つことができます。言い換えればターゲットアクションはNSControllerクラスにおいて定義されています。そしてこれらのNSControllerのサブクラスはコントローラ、コントローラオブジェクト、コントローラクラスなどと呼ばれます。具体的なクラス名で言えばNSButton、NSSlider、NSTextFieldなどがあげられます。つまりターゲットアクションはGUIパーツの中のいくつかだけが持っているデザインパターンになります。
ここでこの章で出てくるクラスの継承階層図を見てみましょう。すでに登場してきたものも、これから登場するものも含まれています。
上からルートクラス→サブクラス→サブクラス→サブクラス→サブクラス(末端のクラス)という並びいなっていますが、矢印は上から下にではなく、下から上に伸びています。
私たちは、このような継承関係を表す図としては家系図などを見なれていると思います。その感覚からすると矢印が下から伸びていることには違和感を覚えます。しかしこれはサブクラスがスーパークラスのすべてを含んでいるという関係、言い換えれば参照しているという関係を表しています。
OOPの継承階層を表す場合にはこのようにサブクラスからスーパークラスへ矢印を引く決まりになっています。慣れるまでは少し気持ちが悪いかもしれませんが我慢してください。
各クラスには代表的なメソッドを載せました。それぞれのクラスがどのような役割を担っているか確認してみてください。分かるメソッドもあれば分からないメソッドもあると思いますが、ひとつひとつリファレンスで確かめてみることをおすすめいたします。
では実際にMyClipにターゲットアクションの機能を追加してみましょう。
前項の説明で分かっていただけと思いますがターゲットアクションは必ずGUIパーツ(ビューパーツ)に搭載することになります。ということはまずはInterface Builderでターゲットアクションを搭載するユーザインタフェース(GUIパーツ)を作成しなければなりません。なお実際のターゲットアクションの搭載はデリゲートの場合とおなじくInterface Builderで行うこともコーディングで行うこともできます。
Interface Builderでの作業の前にターゲットアクションの実行結果を確かめるための仕掛けを作っておきたいと思います。
Controller.mを開きtextDidChange:メソッドの次に
- (IBAction)indicate:(id)senderというメソッドを追加します。そしてtextDidChange:メソッドから
NSLog(@”%@”, [model string]);という式をindicate:メソッドに移動します。当然カット&ペーストで行ってもらって構いません。この作業でController.mのtextDidChange:メソッドとindicate:メソッドのコードは次のようになります。強調箇所が追加されたコードになります。
この作業で何をしているかというと、Text Viewを書き変えるたびにModelオブジェクトのstringインスタン変数の値(文字列)がコンソールに表示されていたのを、indicate:メソッドが実行された時にだけコンソールに表示されるように変更しています。コーディングが終わりましたらController.mを保存してください。- (void)textDidChange:(NSNotification *)aNotification { [model setString:[[textView string] copy]]; } - (IBAction)indicate:(id)sender { NSLog(@"%@", [model string]); }
- (IBAction)indicate:(id)sender次にController.hを開きます。Contoroller.hの@endの前の行にさきほどコピーしたシグネチャをペーストします。ペーストしたシグネチャの最後に式の終わりを示す ; (セミコロン )を忘れずに付けてください。この作業でController.hのコードは次のようになります。強調表示された部分が追加されたコードです。
この作業でController.hに追加されたのはindicateメソッドのプロトタイプ(メソッド宣言)です。戻り値としてIBActionと記述されていますが、IBActionと記述することによってInterface Builderでこのメソッドactionとしてを認識できるようになります。このactionメソッドの引数は#import <Cocoa/Cocoa.h> #import "Model.h" @interface Controller : NSObject { Model *model; IBOutlet NSTextView *textView; } - (IBAction)indicate:(id)sender; @end
(id)senderとする決まりになっています。またIBActionという文字列はコンパイルに先立つプリプロセスでvoidに置き換えられます。
次にInterface Builderでの作業を行います。
MainMenu.xibを起動してください。そしてメインウィンドウのタイトルバーをクリックするか、もしくはMainMenu.xibウィンドウでWindow(MyClip)オブジェクトをクリックします。インスペクタウィンドウのタイトルがWindow ○○になっていることを確認してください。
次にメインウィンドウの中をクリックします。メインウィンドウの表示部全体が選択されてインスペクタパネルのタイトルがScroll View ○○になることを確認してください。もしScroll Viewが選択されていないようでしたら、メインウィンドウを選択するところからやり直してみてください。
Scroll Viewを選択するとウィンドウの下辺の中央に小さい点(ドット)があることが分かると思います。
図 MyClipウィンドウ2
次にこの点(ドット)をマウスでつかんで(ドラッグして)スクロールビューの下辺を少し上に持ち上げます。
図 MyClipウィンドウ3
ライブラリパネルからPush Buttonを探して、メインウィンドウの下に空けたスペースにドラッグします。その際にレイアウトの目安となるガイドラインが現れますのでそれにあわせてボタンをドロップします。
図 Button レイアウト
新しく配置したボタンが選択された状態のままインスペクタパネルでAttributesタブを選びます。インペクタパネルのタイトルが Button Attributesになっていることを確認してください。そしてTitle欄をIndicateにします。
図 Button Attributes
同じく、Push Button を選択したまま「Layout」メニューから「Size to Fit」を選びます。ボタンがタイトル文字に合うサイズに変わります。ボタンのサイズが変わりましたのでもう一度ガイドラインにあわせてボタンの位置決めをしてください。
図 Layout - Size To Fit
Scroll View を再び選択し下辺の丸い点をドラッグして現れるガイドラインにしたがってScrool Viewの下辺の位置を調整します。
図 Scroll View レイアウト
以上でユーザインタフェースは完成いたしました。
目次 | < 前ページ 次ページ > |