『逆引きリファレンス』へ戻る

アクションが実行される仕組みとは

対象:[RubyCocoa][MacRuby][Mac OS X 10.5(Leopard)][Mac OS X 10.6(Snow Leopard)]

通常、Macのアプリケーション開発ではInterface Builderを使って、ボタンを押す、検索キーワードを入力するといったイベントに対して処理(アクション)を割り当てます。具体例として、ボタンを押したときに「Hello World!」と表示するhelloアクションを割り当てるには、(1)Interface Builder上で[control]キーを押しながらボタンをドラッグし、(2)helloアクションを持ったオブジェクトの上にドロップし、(3)「hello:」を選択します(図1)。このアプリケーションをビルド・実行して、ボタンを押すと「Hello World!」と表示されます。

about-target-action-paradigm_001
図1:Interface Builderを使ったアクションの割り当て

ここでは、イベントが発生したときにアクションが実行される仕組みについて説明します。

コントロール(NSControlクラス)

Cocoaでは、ボタン、テキストフィールド、スライダーなどのユーザが操作することでイベントが発生し、アクションを実行できるGUI部品のことを コントロール(control) と呼びます(図2)。

about-target-action-paradigm_002
図2:コントロール

コントロールには次の役割があります。()内はボタンでの説明です。

1. GUI部品を描画する(メインウインドウ上にボタンを表示できる)
2. ユーザのイベントに反応する(ボタンをクリックできる)
3. アクションを実行する(ボタンをクリックすると「Hello World!」と表示する)

Cocoaが提供しているコントロールには、上記の1と2は実装されています。また、3についてはアクションを実行するための仕組みが用意されているため、アプリケーションの開発者はアクションの実装に専念できます。

コントロールは、それを表現するための抽象クラスである NSControlクラス を継承して実装されています。例えば、ボタンを表現するNSButtonクラス※1は、次のような継承関係になっています。

※1:RubyCocoaでは、Cocoaのクラスは全てOSXモジュールに定義されています。例えば、CocoaのNSButtonクラスは、RubyCocoaではOSX::NSButtonクラスとして扱います。以下の説明では、Cocoaのクラス名をそのまま使用しています。実際に、RubyCocoaでそれぞれのクラスを使用するときは、クラス名の先頭に「OSX::」を付けるか、各クラスを使用する前に「include OSX」を記述してください。なお、MacRubyではCocoaのクラス名をそのまま使用できます。
NSObject
> NSResponder
  > NSView
    > NSControl
      > NSButton

当然、テキストフィールド(NSTextFieldクラス)、スライダー(NSSliderクラス)もNSControlクラスを継承しています。(図3)

about-target-action-paradigm_003
図3:コントロールの継承関係

ターゲット/アクションパラダイム

アクションは、特定のクラスのインスタンスメソッドとして実装します。例えば、以下のように「Hello World!」と表示するhelloアクションをAppController#helloメソッドとして実装します。

▼RubyCocoaの場合
class AppController < OSX::NSObject
  ib_action :hello

  def hello(sender)
    # 「Hello World!」と表示する処理
  end
end
▼MacRubyの場合
class AppController
  def hello(sender)
    # 「Hello World!」と表示する処理
  end
end

次に、コントロールにレシーバとインスタンスメソッド名を格納します。それぞれNSControl#target=メソッドとNSControl#action=メソッドを使います。また、コントロールに格納したレシーバのことを ターゲット と呼びます。例えば、AppControllerクラスのインスタンスがcontroller変数、ボタンがbutton変数にそれぞれ代入されているとすると、以下のようにしてコントロールにレシーバとインスタンスメソッド名を格納できます。Interface Builderを使ってイベントにアクションを割り当てることができますが、その裏で以下と同じことが行われています。

▼RubyCocoaの場合
button.target = controller
button.action = "hello"
▼MacRubyの場合
button.target = controller
button.action = "hello:"

そして、ユーザの操作などによってイベントが発生してアクションを実行するときには、先ほど格納した情報を使って、レシーバのインスタンスメソッドが呼び出されます。この処理を無理矢理Rubyで表現するならば、以下のような感じです。

▼アクションの実行をRubyで表現すると...
@target.send(@action, self)

上記のようにしてアクションを実行する仕組みのことを ターゲット/アクションパラダイム と呼びます。

『逆引きリファレンス』へ戻る