2014-06-14 5 views
28

Swift에서 새로운 문서 기반 Cocoa 프로젝트를 시작하려고하고 NSWindowController (문서 기반 응용 프로그램의 Apple 가이드에서 권장)의 하위 클래스를 만들고 싶습니다. ObjC에서는 NSWindowController 하위 클래스의 인스턴스를 initWithWindowNibName: 메시지를 보내도록 만듭니다.이 메시지는 그에 따라 구현되어 superclasses 메서드를 호출합니다.Swift에서 NSWindowController 서브 클래 싱 및 init (windowNibName)

Swift에서 init(windowNibName)은 편의 초기화 프로그램으로 만 사용할 수 있으며 NSWindowController의 초기화 지정자는 init(window)이며 이는 분명히 창에 전달하기를 원합니다.

명시된 이니셜 라이저가 아니기 때문에 super.init(windowNibName)을 내 하위 클래스에서 호출 할 수 없으므로 분명히 convenience init(windowNibName)을 구현해야합니다. 그러면 self.init(window)을 호출해야합니다. 하지만 내가 가지고있는 모든 것이 nib 파일 인 경우 nib 파일의 창에 액세스하여 이니셜 라이저로 보내려면 어떻게해야합니까?

답변

14

당신은 오버라이드 (override) 할 필요가 중 하위 클래스가 자동으로 init(windowNibName) 다른 모든 편리 이니셜을 상속하고 당신이 그것을 구성 할 수있는 경우에 NSWindowController (init(), init(window)init(coder)), 또는 그들 중 누구도 모두 세 개의 지정된 이니셜, 사용하는 슈퍼 클래스의 편의 이니셜 :

// this overrides none of designated initializers 
class MyWindowController: NSWindowController { 
    override func windowDidLoad() { 
     super.windowDidLoad() 
    } 
} 

// this one overrides all of them 
// 
// Awkwardly enough, I see only two initializers 
// when viewing `NSWindowController` source from Xcode, 
// but I have to also override `init()` to make these rules apply. 
// Seems like a bug. 
class MyWindowController: NSWindowController 
{ 
    init() 
    { 
     super.init() 
    } 

    init(window: NSWindow!) 
    { 
     super.init(window: window) 
    } 

    init(coder: NSCoder!) 
    { 
     super.init(coder: coder) 
    } 

    override func windowDidLoad() { 
     super.windowDidLoad() 
    } 
} 

// this will work with either of the above 
let mwc: MyWindowController! = MyWindowController(windowNibName: "MyWindow") 

이는 "초기화/자동 이니셜 상속"에 포함되는 언어 가이드 :

그러나 특정 조건이 충족되면 수퍼 클래스 이니셜 라이저가 자동으로 상속됩니다. 실제로 이는 많은 일반적인 시나리오에서 초기화 프로그램 재정의를 작성할 필요가 없으며 안전하게 할 수있을 때마다 최소한의 노력으로 수퍼 클래스 초기화 프로그램을 상속받을 수 있음을 의미합니다.

당신이 하위 클래스에서 소개하는 새로운 속성에 대한 기본 값을 제공한다고 가정하면, 다음과 같은 두 가지 규칙이 적용

규칙 서브 클래스가 지정된 초기화를 정의하지 않는 경우 1 , 그것은 자동으로 모든 상속 그것의 슈퍼 클래스 지정 이니셜 라이저.

규칙 2 서브 클래스는 슈퍼 클래스 지정의 모든 구현 제공하는 경우 초기화를-중 규칙 1에 따라이를 상속에 의해, 또는의 한 부분으로 사용자 정의 구현을 제공함으로써 정의 - 그것은 자동으로 모든 상속 슈퍼 클래스 편의 초기화 프로그램

+2

그렇지 않으면, 클래스의 속성으로 정의 NSWindowController 인스턴스를 저장 한 후, 신원 관리자의 사용자 정의 NSWindowController 클래스를 사용하여 윈도우에 윈도우 출구를 드래그하고 펜촉의 FileOwner를 설정해야합니다 쓰레기 수거. –

4

편의 초기화 프로그램을 호출하고 사용자 지정 변수를 수정 한 다음 새 개체를 반환하는 클래스 메서드 만 있으면이 문제를 해결할 수있었습니다.

그래서 오브젝티브 C init 방법은 다음과 같을 것이다 :

class PPPluginInfoController: NSWindowController { 
    private var info: PPPlugInInfo! 
    class func windowControllerFromInfo(plugInfo: PPPlugInInfo) -> Self { 
     var toRet = self(windowNibName:"PPPlugInInfoController") 
     toRet.info = plugInfo 

     return toRet 
    } 
} 
+1

훌륭한 아이디어입니다.이 옵션이 가장 좋습니다. 비록 내가이 게시물을 찾았지만 (적어도이 경우에는) windowNibName을 오버 라이딩하는 것이이 문제를 해결하지만, 옵션이 아닌 프로퍼티 (var info)를 옵션으로 만드는 것을 끝내는 것이 싫지만, – logancautrell

+0

이 게시물을 찾았습니다. http://dev.eltima.com/post/91454912064/nswindowcontroller-subclass-in-swift-project – logancautrell

-1

업데이트가 대답을 hamstergene하기 :

//Class.h 
@class PPPlugInInfo; 

@interface PPPlugInInfoController : NSWindowController 
//... 
- (id)initWithPlugInInfo:(PPPlugInInfo *)plugInfo; 
//... 
@end 

//Class.m 
#include "Class.h" 

@interface PPPlugInInfoController() 
@property (strong) PPPlugInInfo *info; 
@end 

@implementation PPPlugInInfoController 

- (id)initWithPlugInInfo:(PPPlugInInfo *)plugInfo; 
{ 
    if (self = [self initWithWindowNibName:@"PPPlugInInfoController"]) { 
     self.info = plugInfo; 
    } 
    return self; 
} 

@end 

이 내가 스위프트 버전을했던 방법이다.

Xcode 버전 6에서 정상적으로 작동합니다.1 (6A1052d)

Add your custom class to window controller

// 
// MainWindowController.swift 
// VHDA Editor 
// 
// Created by Holyfield on 20/11/14. 
// Copyright (c) 2014 Holyfield. All rights reserved. 
// 

import Cocoa 

class MainWindowController: NSWindowController { 

    //override func windowDidLoad() { 
    // super.windowDidLoad() 

     // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 
    // } 

    override init() 
    { 
     super.init() 
     println(__FILE__, __FUNCTION__) 
    } 

    override init(window: NSWindow!) 
    { 
     super.init(window: window) 
     println(__FILE__, __FUNCTION__) 
    } 

    required init?(coder: (NSCoder!)) 
    { 
     super.init(coder: coder) 
     println(__FILE__, __FUNCTION__) 
    } 

    override func windowDidLoad() { 
     super.windowDidLoad() 
     println(__FILE__, __FUNCTION__) 
    } 

} 

콘솔 출력 : @의 hamstergene의 대답 천재의

(…/MainWindowController.swift, init(coder:)) 
(…/MainWindowController.swift, windowDidLoad()) 
1

스트로크가 NSResponder에서 상속되는뿐만 아니라 init()을 무시하는 것입니다. 지금은 사용자 정의 창 컨트롤러 무엇 nib 파일에에게 더 이상 필요하지 않습니다

class WindowController: NSWindowController { 

    var note: Document! // must be optional because self is not available before delegating to designated init 

    convenience init(note: Document) { 
     self.init(windowNibName: NoteWindowName) 
     self.document = document 
    } 

    override init(window: NSWindow?) { 
     super.init(window: window) 
    } 

    required init?(coder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    override init() { 
     fatalError("init() has not been implemented") 
    } 
} 

: 이제 한 차례는 세 지정 initialisers이 무시되면 을 상속입니다 self.init(windowNibName: NoteWindowName)에 새로운 initialiser 위임을 도입 할 수 있습니다 에서로드하십시오. 대신, 처음에는 하위 클래스에 동기를 부여하는 것이 무엇이든 전문화 될 수 있습니다. 예를 들어, 어떤 문서 계층에 참여하는 것과 같이 ...

+0

감사합니다. 신속한 초기화는 엉망입니다. –

8

어떤 init 메소드도 대체하지 않고 단순히 windowNibName 속성을 무시하고 하드 코딩 된 문자열을 반환합니다. 이렇게하면 기본 바닐라 init 메소드를 호출하여 윈도우 컨트롤러를 생성 할 수 있습니다.

class WindowController: NSWindowController { 

    override var windowNibName: String! { 
     return "NameOfNib" 
    } 
} 

let windowController = WindowController() 

나는 펜촉의 이름이 완전히 (그리고 그냥 평범한 쉽게 WindowController()를 호출의) 외부로 노출 결코 창 컨트롤러 클래스 내에 캡슐화하지되어야 구현 세부 그대로 let windowController = WindowController(windowNibName: "NameOfNib")를 호출하는 동안이 선호합니다.

당신이 init 메소드에 추가 매개 변수를 추가하려면

는 다음을 수행 : 사용자 정의 init 메소드 호출 super.init(window: nil)에서

  • . windowNibName 속성으로 초기화하려면 NSWindowController이 표시됩니다.
  • 개체를 구성하기 위해 필요한 init(coder: NSCoder) 메서드를 재정의하거나 fatalError()을 호출하여 사용을 금지하십시오 (런타임시 알림).
class WindowController: NSWindowController { 

    var test: Bool 

    override var windowNibName: String! { 
     return "NameOfNib" 
    } 

    init(test: Bool) { 
     self.test = test 
     super.init(window: nil) // Call this to get NSWindowController to init with the windowNibName property 
    } 

    // Override this as required per the class spec 
    required init?(coder: NSCoder) { 
     fatalError("init(coder:) has not been implemented. Use init()") 

     // OR 

     self.test = false 
     super.init(coder: coder) 
    } 
} 

let windowController = WindowController(test: true)