イッツァハローワールド

恥さらしていこうかなとか。

xibを使ってソースコードから表示しようとした時にapplicationDidFinishLaunchingが呼ばれなくて困った話(OS X App)

最近は上京してOSX Appを書いている人です。

困りごと(ていうか届かぬ文句)

  • AppKitまわりの資料が少ない
  • AppKitまわりの資料が古い
  • ↑探すくらいならリファリンス読む
  • Swiftとの合わせ技だとめったにない
  • xibとかの話だとあるわけがない

今回の現象

作りたかったもの

  • OS Xアプリで簡易WebブラウザみたいなWindowにWebView乗っけただけのもの。
  • NSWindowControllerでWindowおよびその上のViewイベントの管理をする。
  • 新しいウィンドウを開くみたいなリンクをクリックしたら新しいWindowControllerを生成する。
  • WindowControllerは管理クラスが管理して、Windowを閉じたら管理クラスから抹殺する。
  • WindowControllerの動きは共通かつ、Window内でViewの遷移がないからStoryBoardは使わずxibを使う。

f:id:hanamiju:20150526005540p:plain

やったこと

  • StoryBoardファイルは消す
  • NSWindowControllerがFiles Ownerのxib(CustomWindow.xib)を作る
  • プロジェクト設定のDeployment Info - Main Interfaceを消す
  • AppDelegateのapplicationDidFinishLaunchingで↑のxibからWindowControllerのカスタムクラスを生成
func applicationDidFinishLaunching(notification: NSNotification) {
        var windowController CustomWindowController:  = CustomWindowController(windowNibName: "CustomWindow")
        //...
        self.window = windowController!.window
        self.window!.setFrame(NSScreen.mainScreen()!.frame, display: true, animate: true)
        self.window!.makeKeyWindow()
    }
  • windowDidLoadで管理クラスにWindowControllerを保存、windowWillCloseで管理クラスから削除

ビルド結果

Windowが表示されない。
ていうか、AppDelegateのapplicationDidFinishLaunchingが呼ばれないからWindowが生成されない。

AppDelegateのクラスの宣言時に@NSApplicationMain書けば(デフォルトで書いてあるけど)applicationDidFinishLaunchingが呼ばれると思っていたんだけど違うらしい。

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
// ...

解決策(スマートではないと思うけど...)

要はapplicationDidFinishLaunchingが呼ばれれば良い。

  • 空のMainMenu.xibを用意する。

f:id:hanamiju:20150526011522p:plain 

  • Files Owner(NSApplication)とAppDelegateをDelegateで結ぶ
  • プロジェクト設定のDeployment Info - Main InterfaceをMainMenuと入れる

まとめ

  • だいぶ特殊用途だと思うけど、今回はこんな感じで解決した。
  • すげー時間かかった。空のNib作らなくてもいける方法ある気がしたけど、今回はタイムアップでした。
  • 今回初めてNSWindowController使った。
  • Viewの切り替えがなかったからNSViewController使わなかった。
  • いっぱいWindowあって、いっぱいViewを切り替えるアプリを作るのは骨だなあと思った。