これらは良い質問です。あなたがこの研究を行っており、一緒にハッキングするのではなく、「正しく実行する」方法を学ぶことに関心があるように見えるのは素晴らしいことです。
最初に、MVCデザインパターンに従って、適切な場合にモデルオブジェクトにデータを配置することの重要性に焦点を当てた以前の回答に同意します。厳密に「プレゼンテーション」データでない限り、通常、コントローラ内に状態情報を配置しないようにします。
次に、プログラムでコントローラーをナビゲーションコントローラーにプッシュする方法の例については、スタンフォード大学のプレゼンテーションの10ページを参照してください。Interface Builderを使用してこれを「視覚的に」行う方法の例については、このチュートリアルをご覧ください。
3番目、そしておそらく最も重要なこととして、スタンフォード大学のプレゼンテーションで言及されている「ベストプラクティス」は、「依存性注入」設計パターンのコンテキストで考えると、はるかに理解しやすいことに注意してください。簡単に言うと、これは、コントローラーが、ジョブを実行するために必要なオブジェクトを「ルックアップ」してはならないことを意味します(たとえば、グローバル変数を参照する)。代わりに、それらの依存関係を常にコントローラーに「注入」する必要があります(つまり、メソッドを介して必要なオブジェクトを渡します)。
依存関係注入パターンに従うと、コントローラーはモジュール式になり、再利用可能になります。そして、スタンフォードのプレゼンターがどこから来ているのか(つまり、Appleの従業員としての仕事は、簡単に再利用できるクラスを構築すること)を考える場合、再利用性とモジュール性は高い優先順位です。彼らがデータを共有するために言及するすべてのベストプラクティスは、依存関係注入の一部です。
それが私の返事の要点です。役立つ場合に備えて、以下のコントローラーで依存性注入パターンを使用する例を示します。
ビューコントローラーでの依存性注入の使用例
複数の本が一覧表示されている画面を作成しているとします。ユーザーは購入したい本を選び、「チェックアウト」ボタンをタップしてチェックアウト画面に移動できます。
これを構築するには、GUI /ビューオブジェクトを制御および表示するBookPickerViewControllerクラスを作成します。すべての書籍データはどこで取得されますか?それはそのためのBookWarehouseオブジェクトに依存しているとしましょう。したがって、コントローラーは基本的にモデルオブジェクト(BookWarehouse)とGUI /ビューオブジェクトの間でデータを仲介しています。言い換えると、BookPickerViewControllerはBookWarehouseオブジェクトに依存します。
これを行わないでください:
@implementation BookPickerViewController
-(void) doSomething {
// I need to do something with the BookWarehouse so I'm going to look it up
// using the BookWarehouse class method (comparable to a global variable)
BookWarehouse *warehouse = [BookWarehouse getSingleton];
...
}
代わりに、依存関係は次のように注入する必要があります。
@implementation BookPickerViewController
-(void) initWithWarehouse: (BookWarehouse*)warehouse {
// myBookWarehouse is an instance variable
myBookWarehouse = warehouse;
[myBookWarehouse retain];
}
-(void) doSomething {
// I need to do something with the BookWarehouse object which was
// injected for me
[myBookWarehouse listBooks];
...
}
Apple関係者が委任パターンを使用して「階層を遡って通信する」ことについて話しているとき、彼らは依然依存関係注入について話している。この例では、ユーザーが自分の本を選んでチェックアウトする準備ができたら、BookPickerViewControllerは何をすべきですか?まあ、それは本当にその仕事ではありません。他のオブジェクトに機能を委譲する必要があります。つまり、別のオブジェクトに依存します。したがって、BookPickerViewController initメソッドを次のように変更します。
@implementation BookPickerViewController
-(void) initWithWarehouse: (BookWarehouse*)warehouse
andCheckoutController:(CheckoutController*)checkoutController
{
myBookWarehouse = warehouse;
myCheckoutController = checkoutController;
}
-(void) handleCheckout {
// We've collected the user's book picks in a "bookPicks" variable
[myCheckoutController handleCheckout: bookPicks];
...
}
これらすべての最終結果は、BookPickerViewControllerクラス(および関連するGUI /ビューオブジェクト)を提供して、BookWarehouseとCheckoutControllerが実装可能な汎用インターフェイス(つまりプロトコル)であると想定して、自分のアプリケーションで簡単に使用できることです:
@interface MyBookWarehouse : NSObject <BookWarehouse> { ... } @end
@implementation MyBookWarehouse { ... } @end
@interface MyCheckoutController : NSObject <CheckoutController> { ... } @end
@implementation MyCheckoutController { ... } @end
...
-(void) applicationDidFinishLoading {
MyBookWarehouse *myWarehouse = [[MyBookWarehouse alloc]init];
MyCheckoutController *myCheckout = [[MyCheckoutController alloc]init];
BookPickerViewController *bookPicker = [[BookPickerViewController alloc]
initWithWarehouse:myWarehouse
andCheckoutController:myCheckout];
...
[window addSubview:[bookPicker view]];
[window makeKeyAndVisible];
}
最後に、BookPickerControllerは再利用可能であるだけでなく、テストも簡単です。
-(void) testBookPickerController {
MockBookWarehouse *myWarehouse = [[MockBookWarehouse alloc]init];
MockCheckoutController *myCheckout = [[MockCheckoutController alloc]init];
BookPickerViewController *bookPicker = [[BookPickerViewController alloc] initWithWarehouse:myWarehouse andCheckoutController:myCheckout];
...
[bookPicker handleCheckout];
// Do stuff to verify that BookPickerViewController correctly called
// MockCheckoutController's handleCheckout: method and passed it a valid
// list of books
...
}