Swinject / SwinjectStoryboard

Swinject extension for automatic dependency injection via Storyboard
MIT License
268 stars 142 forks source link

Explicit instantiation for macOS apps #78

Open mpdifran opened 6 years ago

mpdifran commented 6 years ago

The README mentions you can do something like this in iOS apps to explicitly load your root view controller from SwinjectStoryboard:

let window = UIWindow(frame: UIScreen.mainScreen().bounds)
window.makeKeyAndVisible()
self.window = window

let storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil, container: container)
window.rootViewController = storyboard.instantiateInitialViewController()

Is there an equivalent practice for macOS?

jakubvano commented 6 years ago

I don't typically do OSX development, so can't comment on recommended practices. It would definitely be welcomed if someone well versed in OSX apps gave some pointers.

mpdifran commented 5 years ago

My current workaround is to let the app load via storyboard, and then call this method in applicationDidFinishLaunching(_ aNotification: Notification).

func setupWindow() {
    let storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil)

    guard let window = NSApplication.shared.windows.first(where: { $0.delegate is MainWindowController }),
        let mainWindowController = storyboard.instantiateInitialController() as? MainWindowController else { return }

    window.windowController = mainWindowController
    window.makeKeyAndOrderFront(self)
}

One thing to note though (not sure if this is a separate bug or a side effect of doing the above) but I'm noticing storyboardInitComplete() is called after windowDidLoad(). This behavior is different than on iOS, where they're called in the opposite order.

armintelker commented 5 years ago

@mpdifran Hey i am not sure if I understand you correct but you can remove the storyboard from the Info.plist you need to add your own NSApplication

import Foundation
import Cocoa

class CustomApplication: NSApplication {

    let strongDelegate = AppDelegate()

    override init() {
        super.init()
        self.delegate = strongDelegate
    }

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

}

and you need to add/replace this class to the info plist

    <key>NSPrincipalClass</key>
    <string>your_project_name.CustomApplication</string>

if you have a problem to get the correct project name just start your app and add this line somewhere in your project and you will get in the console your project name.

print(String(describing: self))
class AppDelegate: NSObject, NSApplicationDelegate {
    private var storyboard: SwinjectStoryboard!
    private var windowController: NSWindowController!
    let container = Injections().container

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        storyboard = SwinjectStoryboard.create(name: "Main", bundle: nil, container: container)

        windowController = storyboard.instantiateInitialController() as! NSWindowController?
        windowController?.showWindow(self)
    }
}
mpdifran commented 5 years ago

Ah that's perfect. Thank you!