異なるxibにあるオブジェクト間でのデータ渡し(実装編)

注意事項
前回、異なるxibにあるオブジェクト間で、データを渡す方法について検討した。
検討して浮上した案は4つ。今回はその4つの案の実装を試みる。

■前回の案を実際に実装

前回検討した案は以下の通り。

・案1:NSWindowController経由
・案2:AppDelegate経由
・案3:クラス内グローバル変数
・案4:NSNotificationCenter経由

これらの案の実装として、メインウインドウに入力した文字をサブウインドウで表示するプログラムを作成する。

完成イメージ
f:id:nashikachi:20160911224716p:plain

■案1:NSWindowController経由

案1では、メインウインドウのテキストフィールドのデータをNSWindowControllerサブクラス経由で、サブウインドウがあるxib側のオブジェクトに渡している。

実際のプログラムはこちら。
GitHub - tnbinkttm203582/MultiWindowSample1: 異なるxibのオブジェクト間のデータ渡し 案1

AppControllerがSubWindowControllerを作ったあと、AppControllerがSubWindowControllerに、テキストフィールドの文字列を渡している。文字列を受け取ったSubWindowControllerは、そのままSubWindowAppControllerに渡している。
また、テキストフィールドの編集が完了する度に、SubWindowAppControllerへ文字列を渡している。
なおサブウインドウの文字列表記は、SubWindowAppControllerにあるtestStr変数にbindさせて表示している。

■案2:AppDelegate経由

AppDelegateにデータを置く方法は非常に簡単。
①最初から作成されているappDelegateに、受け渡したい変数とそのアクセサメソッドを追記。
②渡す側のオブジェクトで、プログラム共通のappDelegateのインスタンスを呼び出し、渡したいデータをセット。
③受け取る側のオブジェクトでappDelegateのインスタンスを呼び出し、データを取得。

appDelegateの呼び出しは以下の通り。

AppDelegate *appDele =  (AppDelegate *) [[NSApplication sharedApplication] delegate];

あとは呼び出したappDelegateインスタンスにデータをセットしたり取り出したりすればよい。

ただし案1と違って、「誰が」、「いつ」SubWindowAppControllerにデータをセットすればいいのか考える必要がある。
案1では、中継役のSubWindowControllerが SubWindowAppControllerへのデータ渡しも担ってくれた。しかし案2では、中継役のAppDelegateがSubWindowAppControllerへデータを渡してくれない(渡したい相手のSubWindowAppControllerを知らないため)。
そのため、誰かが何かしらのタイミングで、AppDelegateに仮置きしているデータをSubWindowAppControllerにセットしなければならない。
「誰が」の観点はあまり問題でなく、特に目的がなければ SubWindowAppController自身でいい。
問題は「いつ」で、本来であればサブウインドウが作成(表示)された時と、テキスト入力が完了した時に、AppDelegateによる受け渡しが実現できなければならない。そのタイミングを一番簡単に合わせる方法は、案1でやったSubWindowControllerを使う方法だと思う。
なので、タイミングの周知をSubWindowControllerに頼ってデータ渡しはAppDelegateを使う、という合わせ技もありだが、そこまでするなら全て案1でええやんとなる。

ちなみに、案3も案2と同じこの問題を抱えている。
この問題の続きは案3の説明で。

■案3:クラス内グローバル変数

案3も、共通的に利用できるオブジェクトにデータを仮置きするという点では案2と変わらない。そのため、案2で説明した「いつデータを取り出すか」の問題も同様に存在する。

このプログラムにおいては、
 ①サブウインドウを作成時
 ②メインウインドウのテキストフィールドの編集完了時
の2つのタイミングでデータを仮置きオブジェクトから取り出せればいい。

受け手であるSubWindowAppControllerがNSTimerを使ったループでポーリングして取得する方法もあるが、あまりに力技なのでもう少し別の方法を考える。送り手であるAppControllerが何らかの手法でSubWindowAppControllerに伝えることができれば一番いい。その手法として、NSNotificationCenter を使った通知がある。

NSNotificationCenter を使えば、異なるオブジェクト間でイベント通知が可能になる。SubWindowAppControllerが通知を待ち受け、①と②を行った際にAppControllerが通知すれば、適切なタイミングに処理できる。

実際のプログラムはこちら。
GitHub - tnbinkttm203582/MultiWindowTest3: 異なるxibのオブジェクト間のデータ渡し 案3

このNSNotificationCenterを使った通知方法は、案2でも有効。

ただ、NSNotificationCenterの通知には、通知でオブジェクトを引数にできる。つまり、NSNotificationCenter単体でデータ渡しができるため、結局NSNotificationCenterを使うなら案2も案3もいらないのではと思わざるを得ない。もしかすると、プログラムによってはNSNotificationCenter+案2,3 という構成が効果的な場合もあるかもしれないが……。

■案4:NSNotificationCenter経由

案3で解説した通り、NSNotificationCenterでは通知と同時にオブジェクト渡しもできる。案3のサンプルプログラムのNSNotificationCenter処理を少し書き換えるだけでそれはできると思う。詳しい方法はNSNotificationCenterの使い方をリファレンス等で確認してほしい。

■まとめ

データ渡しのタイミングさえ気にしなければ、4通りの手法を取れることが分かった。タイミングが問題になるプログラムの場合は、案1か案4の処理が必要になる。

タイミングを気にしないのであれば、案2のAppDelegateを使う方法が一番簡単だった。ただAppDelegateは使い易いため、考えなしに実装していくと何でもかんでもここに書いてしまうそうなので、リソースや保守性で注意は必要だと感じた。何でもかんでも、の点でいえば案4のNSNotificationCenterによる通知もそうで、これも頼りすぎないようにしたい。

それぞれ一長一短があるので作りたいプログラムの設計に合わせて使っていきたい。