In a Swift 2.0, Single Page Application project, in XCode 7.0.1, with the Swift dependency injection framework Swinject, I am doing the following:
DuplicateProtocol.swift:
protocol DuplicateProtocol { var id: String { get } }
SingletonProtocol.swift:
protocol SingletonProtocol { var id: String { get } }
DuplicateProxy.swift
class DuplicateProxy: DuplicateProtocol {
let id: String
init ( id: String ) {
self.id = "DuplicateProxy." + id
}
}
SingletonProxy.swift:
class SingletonProxy: SingletonProtocol {
let id: String
init ( id: String ) {
self.id = "SingletonProxy." + id
}
}
ViewController.swift:
import UIKit
class ViewController: UIViewController
{
var duplicate: DuplicateProtocol?
var singleton: SingletonProtocol?
required init? ( coder aDecoder: NSCoder ) {
print( "ViewController.init?", duplicate, singleton )
super.init( coder: aDecoder )
}
override func viewDidLoad () {
print( "ViewController.viewDidLoad", duplicate, singleton )
super.viewDidLoad()
}
}
AppDelegate.swift:
import Swinject
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{
var window: UIWindow?
func application ( application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]? ) -> Bool {
let container = Container()
let singleton = SingletonProxy( id: "first" )
container.register( SingletonProtocol.self ) { _ in singleton }
container.register( DuplicateProtocol.self ) { _ in DuplicateProxy( id: "second" ) }
container.registerForStoryboard( ViewController.self ) {
r, c in c.duplicate = r.resolve( DuplicateProtocol.self )
}
print( "AppDelegate.application" )
return true
}
}
And this is the console log I am unfortunately getting:
ViewController.init? nil nil
AppDelegate.application
ViewController.viewDidLoad nil nil
Put as simply as I can: what changes do I need to make? Thank you, JBM.
Initializer injection is not available if you want to instantiate the view controller from a storyboard because UIKit framework calls init?(coder:)
.
Instead, property injection should be used to instantiate it from a storyboard:
class SomeViewController: UIViewController {
var duplicate: DuplicateProtocol?
var singleton: SingletonProtocol?
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
}
}
UPDATE
Still the implicit instantiation of UIWindow and the initial view controller is not supported by Swinject. You need to instantiate them explicitly as the following example does.
import Swinject
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var container: Container {
let container = Container()
let singleton = SingletonProxy( id: "first" )
container.register( SingletonProtocol.self ) { _ in singleton }
container.register( DuplicateProtocol.self ) { _ in DuplicateProxy( id: "second" ) }
container.registerForStoryboard( ViewController.self ) {
r, c in c.duplicate = r.resolve( DuplicateProtocol.self )
}
return container
}
func application ( application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]? ) -> Bool {
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()
return true
}
}
By the way, you don't have to handle the singleton instance by yourself. Swinject has Singleton (aka Container) Object Scope, which can be set with .inObjectScope(.Container)
as documented here.
UPDATE 2
Swinject version 0.3 supports the implicit instantiation of UIWindow and its root view controller from "Main" storyboard. Here is its documentation.