2
import Foundation
import RentalsService

class RentalsViewController: UIViewController {

    var rentalService: Rentals

    init(rentalService: Rentals) {
        self.rentalService = rentalService
        super.init(nibName: "RentalsViewController", bundle: NSBundle.mainBundle())

    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder) // problem here
    }

}

I want rentalService variable to be non-optional. i.e. you can't have a rentalsVC without the service. However, I'm forced to declare init(NSCoder) - but I don't have access to a rental service implementation at this point.

Rentals is a protocol, and I'm using dependency injection - so one doesn't create the dependency inside the class.

Anyone got any clever ideas to overcome this? Or what is the preffered pattern / best practice?

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
bandejapaisa
  • 26,576
  • 13
  • 94
  • 112

2 Answers2

1

You can do this if you don't want to support NSCoding:

required init(coder: NSCoder) {
  fatalError("NSCoding not supported")
}

As referenced here: https://stackoverflow.com/a/25128815/2611971

Community
  • 1
  • 1
Logan
  • 52,262
  • 20
  • 99
  • 128
  • Thanks for this. This is what I ended up doing as I don't support NSCoding - my ViewController needs to be constructed with it's default init method with the dependencies it has, so it won't be loaded/unarchived via a nib file. – bandejapaisa Oct 14 '14 at 20:47
-1

Depending on which DI framework you're using, the way I'd fix it is by using setter injection rather than constructor injection.

In that case you have to either provide an initial fake value to the property at initialization time, or convert the property to optional. In the latter case, I'd declare it as implicitly unwrapped:

var rentalService: Rentals!

to avoid unwrapping it explicitly at every usage.

Another solution, which I am using in my own DI framework, is to initialize properties lazily and inline, for example:

private lazy var _router: IRouter = { Injector.instance.instanceForType(IRouter.self) as IRouter }()

Here I know the interface, and I ask the injector to provide me an instance of whichever the bound type is. During app initialization I link interfaces to implementation statically.

Antonio
  • 71,651
  • 11
  • 148
  • 165
  • I'm not using a DI framework, just rolling my own. Also, not a fan of setter injection - i like the concept of an object only being able to be constructed in a valid state during initialization. Your own DI framework looks like an interesting technique, I'd like to see an example of the static linking app initialisation and how it switches in a unit test. Thanks – bandejapaisa Oct 14 '14 at 20:39
  • Unfortunately I can't provide any code because I don't have permission to release it (it's not my own project). I can just say that I bind interfaces to instances with code like this: `injector.bindInterface(IRouter.self, toImplementation: Router.self, asSingleton: true) { Router() }`. However this DI library has a severe limitation: it works with objc compatible classes only (so no use of generics etc.). In testing, I just bind the interface to another class if I need to. – Antonio Oct 14 '14 at 20:51
  • Interesting. Thanks for this. – bandejapaisa Oct 14 '14 at 21:36