Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass arguments to the resolve method when using Swinject?

I have a test project that I'm trying to pass an argument to the resolve method in a Swinject project.

Here is an example of what my Swinject storyboard extetion file has in it.

import Swinject

extension SwinjectStoryboard {

    class func setup() {

        let mainDm = MainDM()

        defaultContainer.register(MainDM.self) { _ in
            mainDm
        }

        defaultContainer.registerForStoryboard(ViewController.self) { r, c in
            c.dm = r.resolve(MainDM.self)
            c.container = defaultContainer

        }


        defaultContainer.register(GetMessageAction.self) { _, delegate in
            GetMessageAction(dm:mainDm, delegate: delegate)
        }

    }

}

in my ViewController I'm trying to do the following to resolve the GetMessageAction

@IBOutlet weak var myText: UILabel!

    var dm:MainDM!
    var container:Container!

    override func viewDidLoad() {
        super.viewDidLoad()

        NSTimer.scheduledTimerWithTimeInterval(NSTimeInterval(3), target: self, selector: #selector(ViewController.getMessage), userInfo: nil, repeats: false)

    }

    func getMessage() {

        let action:GetMessageAction? = container.resolve(GetMessageAction.self, argument: self)!
        action?.execute()

    }

I get the following message when my getMessage function runs

fatal error: unexpectedly found nil while unwrapping an Optional value

like image 517
mattwallace Avatar asked Jun 11 '16 19:06

mattwallace


2 Answers

As resolving with arguments is dependent on exactly matching types of arguments, you need to downcast passed object:

container.resolve(GetMessageAction.self, argument: self as GetMessageActionDelegate)!

Assuming that GetMessageActionDelegate is the type of delegate passed in constructor GetMessageAction(dm:delegate:).

like image 80
Jakub Vano Avatar answered Oct 27 '22 04:10

Jakub Vano


The swift file of the ViewController you have created in your Storyboard must declare init(NSCoder), it is actually not mentioned in the README.md, I'm thinking about opening an issue regarding this...

   required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

You can take a look at my open source project using exactly this technique, I am setting up the dependencies using the extension of SwinjectStoryboard here for example the LoadingDataVC.

extension SwinjectStoryboard {
    class func setup() {

        defaultContainer.register(HTTPClientProtocol.self) { _ in
            HTTPClient()
        }.inObjectScope(.Container)

        defaultContainer.register(APIClientProtocol.self) { r in
            APIClient(
                httpClient: r.resolve(HTTPClientProtocol.self)!
            )
        }.inObjectScope(.Container)

        defaultContainer.register(ImagePrefetcherProtocol.self) { _ in
            ImagePrefetcher()
        }.inObjectScope(.Container)

        defaultContainer.registerForStoryboard(GameVC.self) { r, c in
            c.imagePrefetcher = r.resolve(ImagePrefetcherProtocol.self)
        }

        defaultContainer.registerForStoryboard(LoadingDataVC.self) { r, c in
            c.apiClient = r.resolve(APIClientProtocol.self)
            c.imagePrefetcher = r.resolve(ImagePrefetcherProtocol.self)
        }
    }
}

Once you have the required init it should work! :)

like image 41
Sajjon Avatar answered Oct 27 '22 04:10

Sajjon