7

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

Yoichi Tagaya
  • 4,547
  • 2
  • 27
  • 38
mattwallace
  • 4,132
  • 6
  • 43
  • 77

3 Answers3

3

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:).

Jakub Vano
  • 3,833
  • 15
  • 29
  • doing this I still get the following error fatal error: unexpectedly found nil while unwrapping an Optional value – mattwallace Jun 13 '16 at 21:00
1

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! :)

Sajjon
  • 8,938
  • 5
  • 60
  • 94
0

Use either of the following methods of a storyboard to get a view controller registered by registerForStoryboard.

  • instantiateViewControllerWithIdentifier
  • instantiateInitialViewController

https://github.com/Swinject/Swinject/blob/v1/Documentation/Storyboard.md https://github.com/Swinject/SwinjectStoryboard/issues/5

Yoichi Tagaya
  • 4,547
  • 2
  • 27
  • 38
  • This doesn't explain why I can't pass an argument to the resolve(GetMessageAction.self, argument:self) – mattwallace Jun 12 '16 at 15:24
  • I'm sorry for my misunderstanding. I didn't have time to read your question carefully. – Yoichi Tagaya Jun 12 '16 at 16:12
  • I think you instantiated `ViewController` by its initializer, not by `instantiateViewControllerWithIdentifier` or `instantiateInitialViewController`. That's why `container` property of `ViewController` did not get injected and you got the error. If you use the either of `instantiate*` methods, I think `resolve` method for `GetMessageAction` with the argument should work because the `container` property is injected and it is not `nil`. – Yoichi Tagaya Jun 16 '16 at 14:31
  • I tried your suggestion and followed documentation and for whatever reason this is still not working. If I inspect the container in the ViewController I see the services and keys to all the objects but it's not returning my class. Could you have a look at my project in order to get more context and see what I might be doing wrong ? https://www.dropbox.com/s/gqjrn5b1ysyautm/Hello%20MVC.zip?dl=0 – mattwallace Jun 18 '16 at 16:45