이것들은 좋은 질문이며, 당신이이 연구를하고 있다는 것을 알기에 훌륭합니다. 단지 그것을 해킹하는 대신 "올바른 방법"을 배우는 것에 관심이있는 것 같습니다.
먼저 , 적절한 경우 (MVC 디자인 패턴에 따라) 모델 객체에 데이터를 넣는 것의 중요성에 중점을 둔 이전 답변에 동의합니다. 일반적으로 컨트롤러는 상태 정보를 엄격히 "표시"하지 않는 한 상태 정보를 컨트롤러에 넣지 않도록합니다.
둘째 , 컨트롤러를 내비게이션 컨트롤러에 프로그래밍 방식으로 푸시하는 방법에 대한 예제는 Stanford 프레젠테이션 10 페이지를 참조하십시오. Interface Builder를 사용하여 "시각적으로"이 작업을 수행하는 방법에 대한 예제는 이 학습서를보십시오 .
제삼 , 그리고 아마도 가장 중요한 것은 스탠포드 프레젠테이션에서 언급 된 "모범 사례"는 "종속성 주입"디자인 패턴의 맥락에서 생각하면 이해하기 훨씬 쉽다는 것입니다. 간단히 말해서, 이것은 컨트롤러가 작업을 수행하는 데 필요한 객체를 "찾아서는"안된다는 것을 의미합니다 (예 : 전역 변수 참조). 대신, 항상 이러한 의존성을 컨트롤러에 "주입"해야합니다 (즉, 메소드를 통해 필요한 객체를 전달).
의존성 주입 패턴을 따르는 경우 컨트롤러는 모듈 식이며 재사용 가능합니다. 그리고 스탠포드 발표자가 어디에서 왔는지 생각한다면 (즉, Apple 직원으로서 쉽게 재사용 할 수있는 클래스를 만드는 것이 중요합니다) 재사용 성과 모듈성이 우선 순위가 높습니다. 데이터 공유에 대해 언급 한 모든 모범 사례는 종속성 주입의 일부입니다.
그것은 나의 반응의 요지입니다. 도움이 될 수 있도록 아래 컨트롤러와 함께 의존성 주입 패턴을 사용하는 예를 포함하겠습니다.
View Controller에서 종속성 주입을 사용하는 예
여러 권의 책이 나열된 화면을 작성한다고 가정 해 보겠습니다. 사용자는 구매하려는 책을 선택한 다음 "체크 아웃"버튼을 눌러 체크 아웃 화면으로 이동할 수 있습니다.
이를 구축하기 위해 GUI / view 객체를 제어하고 표시하는 BookPickerViewController 클래스를 만들 수 있습니다. 모든 도서 데이터를 어디서 얻을 수 있습니까? 그것을 위해 BookWarehouse 객체에 의존한다고 가정 해 봅시다. 이제 컨트롤러는 기본적으로 모델 객체 (BookWarehouse)와 GUI / view 객체간에 데이터를 중개합니다. 다시 말해 BookWarehouse 개체에 대한 BookPickerViewController DEPENDS입니다.
이 작업을 수행하지 마십시오 :
@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];
...
}
애플 팀은 위임 패턴을 사용하여 "계층 구조를 다시 통신"하는 것에 대해 여전히 의존성 주입에 대해 이야기하고 있습니다. 이 예제에서 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
...
}