[OSX] 메인 윈도우 컨트롤러를 앱델리게이트에서 분리하기

iOS 앱의 경우에는 UIApplication 객체가 생성되면 해당 앱의 델리게이트가 런칭 직후의 일을 처리한다. 이 때 앱의 윈도우가 처음으로 표시할 초기 뷰 컨트롤러의 뷰를 윈도우에 보여주게 된다.

그 이후부터는 화면 단위로 각 뷰의 뷰 컨트롤러 및 여러 MVC의 컨트롤러와 여러가지 디자인패턴을 통해 상호작용하면서 앱을 구성하면 된다.

이에 비해 맥용 앱을 Xcode로 작성하고자 하면 이 “메인 컨트롤러”가 다름 아닌 앱 델리게이트 객체라는 점에서 좀 의아하게 생각된다. 즉, 메인 윈도우에 대해서는 별도의 컨트롤러가, 만약 또 다른 윈도를 생성한다면, 역시나 해당 윈도에 대해서는 별도의 컨트롤러가 있어야 하는 것 아니겠냐는 것이다.

이런 화면 단위마다 별도의 MVC를 구성하는 방법은 다음과 같다.

  1. 먼저 인터페이스 빌더 상에 초기에 생성된 MainMenu에 들어있는 윈도는 삭제한다.
  2. 메인 윈도우 뷰 컨트롤러로 쓸 객체를 새로 만든다. MainWindowController 정도?
  3. MainWindowController 객체를 MainMenu 파일에 추가한다. (NSObject를 추가해서 클래스 이름 변경)
  4. nib 파일을 새로 하나 생성한다. 이름은 MainWindow가 되면 되겠다.
  5. IB에서 새로 만든 메인 윈도우 nib의 File’s owner를 새로 생성한 윈도우 컨트롤러로 지정한다. 또한 이 인터페이스 파일의 윈도우를 MainWindowController의 window 아울렛과 연결해준다.
그러면 다음과 같은 순으로 런칭이 시작된다.
  1. 어플리케이션이 런칭되면서 MainMenu.nib 파일을 로딩한다.
  2. nib 파일이 로드되면  nib 파일 내에 정의된 객체를 초기화하고, 이 객체들에게 모두 awakeFromNib 메시지를 보낸다. 따라서 우리가 만든 윈도우 컨트롤러 객체도 이 메시지를 받게 될 것이다.
  3. 윈도 컨트롤러 객체에서 이 메시지를 받으면 메인 윈도우가 들어있는 nib 파일을 로드하고, 윈도를 표시하도록 한다.
즉, 새로 생성한 메인윈도 컨트롤러의 인터페이스 파일에서 window 프로퍼티를 하나 만들어 준다.
@property (assign) IBOutlet NSWindow *window;
이 프로퍼티는 아래와 같이 사용할 수 있다. 이제 메인 윈도의 컨트롤러는 앱 델리게이트와 분리하는데 성공했다.
-(void)awakeFromNib
{
    if (!self.window) [NSBundle loadNib:@"MainWindow" owner:self];
    [self.window makeKeyAndFrontOf:self];
}

이제 앱을 빌드하고 실행해보면 해당 윈도우가 표시될 것이다.