ivlevAstef / DITranquillity

Dependency injection for iOS (Swift)
MIT License
421 stars 32 forks source link

Liibrary crashes when trying to instantinate view controller #98

Closed vchmezov closed 7 years ago

vchmezov commented 7 years ago

Hello! App library crashes when I'm trying to instantiate view controller from container

Here is a component:

class AppComponent: DIComponent{

    var scope: DIComponentScope { return .public }

    func load(builder: DIContainerBuilder){

        builder.register(type: UIStoryboard.self)
            .set(name: "Main")
            .lifetime(.single)
            .initial { DIStoryboard(name: "Main", bundle: nil, container: $0) }

        builder.register(vc: StartupVC.self)
            .initial(useStoryboard: {container in try container.resolve(name: "Main")}, identifier: "startup")

    }
}

AppDelegate:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        let builder = DIContainerBuilder()
        builder.register(component: AppComponent())
        let container = try! builder.build()

        let viewController = try! container.resolve(StartupVC.self)

        self.window = UIWindow(frame: UIScreen.main.bounds)
        self.window?.rootViewController = viewController
        self.window?.makeKeyAndVisible()

        return true
    }

Crash is on this line let viewController = try! container.resolve(StartupVC.self)

fatal error: 'try!' expression unexpectedly raised an error: Cannot found initial method with signature: (DIContainer) throws -> Any. Use: Register type: StartupVC in file: AppComponent.swift on line: 23

Is it a bug or am I doing something wrong? I can send you sample project.

ivlevAstef commented 7 years ago

I'm no home and can't chech this code. It's perhaps bug, But you can use:

class AppComponent: DIComponent{

var scope: DIComponentScope { return .public }

func load(builder: DIContainerBuilder){

    builder.register(type: UIStoryboard.self)
        .set(name: "Main")
        .lifetime(.single)
        .initial { UIStoryboard(name: "Main", bundle: nil) } // !!!!

    builder.register(vc: StartupVC.self)
        .initial(useStoryboard: {container in try container.resolve(name: "Main")}, identifier: "startup")

}

}

Or

class AppComponent: DIComponent{

var scope: DIComponentScope { return .public }

func load(builder: DIContainerBuilder){

    builder.register(type: UIStoryboard.self)
        .set(name: "Main")
        .lifetime(.single)
        .initial { DIStoryboard(name: "Main", bundle: nil, container: $0) } // short: initial(name: "Main", bundle: nil)

    builder.register(vc: StartupVC.self)
}

} ... let storyboard: UIStoryboard= try! container.resolve(name: "Main") let viewController = storyboard.instantiateViewController(identifier: "startup")

The second option is preferable. In the evening of Sunday I can say more precisely.

Write from phone...

vchmezov commented 7 years ago

This works and properly injects view controller properties (not shown in my sample):

let storyboard: UIStoryboard= try! container.resolve(name: "Main")
let viewController = storyboard.instantiateViewController(identifier: "startup")

But it makes me to remember the view controllers and storyboards identifiers. It would be fine if I could keep all the identifiers in the injection components only. Hope the bug is fixable because your library is much more convenient than Typhoon for Swift application.

ivlevAstef commented 7 years ago

of course

ivlevAstef commented 7 years ago

I fix this bug, and write tests. See version 2.3.0.