Using SwinjectStoryboard using in conjunction AssemblyType prevents ViewControllers to be deallocated unless it's is dismissed and presented again.
Xcode (7.3.1), Swinject (1.1.2)
As example I have an Assembler in my AppDelegate and it uses SwinjectStoryboard setup() method to pass to assembler all my AssemblyTypes
extension SwinjectStoryboard {
public static func setup() {
do {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let assemblies: [AssemblyType] = [
AssemblerFoo(),
AssemblerBar()
]
appDelegate.assembler = try Assembler(assemblies: assemblies, container: defaultContainer)
} catch {
}
}
}
A very common example of assembler would be:
final class AssemblerFoo: AssemblyType {
var viewController: FooViewController!
func assemble(container: Container) {
container.registerForStoryboard(FooViewController.self) { (resolver, vc) in
viewController = vc
vc.presenter = resolver.resolve(FooPresenter.self)!
}
container.register(FooPresenter.self) { resolver in
FooPresenterImpl(
interactor: resolver.resolve(FooInteractor.self)!,
view: resolver.resolve(FooView.self)!
)
}
// register interactor
container.register(FooInteractor.self) { resolver in
FooInteractorImpl(dataProvider: resolver.resolve(FooProvider.self)!)
}
// data provider
container.register(FooProvider.self) { _ in
FooProviderImpl()
}
container.register(FooView.self) { _ in
return viewController
}
}
}
After resolving my dependencies in viewcontrollers' viewDidLoad() method the leak vanished and viewcontrollers are deallocated as intended.
Thanks @yuriferretti-luizalabs for sharing the issue馃槂 It needs some investigation.
Would you try avoid using var viewController: FooViewController! in AssemblerFoo? Also I think you shouldn't keep the instance of Assembler in your app delegate.
@yoichitgy I will try that! Thanks
Instances that are strongly referenced by App Delegate (directory or indirectly) are not deallocated. So, please be careful making references from App Delegate.
Please feel free to reopen the issue if you need help.
Hi I know this issue es closed but here it goes anyway:
I'm trying to apply assemblies to my new project. You said the instance of assembler shouldn't be kept on the App Delegate. Im trying to do the best practices I can but I am pretty new to DI and even more to Swinject. I tried to find examples with good practices but couldn't really find any.
Could you please explain where do you think it would be appropiate to set all the dependencies if not the App Delegate?
Thanks for all your work :)
Hi @Mijail in my project I solved this problem using factory like classes that instantiates all my dependencies and returns some entity I'm interested.
They are more less like this exemple:
import Swinject
class Builder {
private let container = Container()
func makeViewController() -> UIViewController {
container.register(FooProtocol.self) { resolver in
// returns your foo implementing instance
}
container.register(BarProtocol.self) { resolver in
// returns your bar implementing instance
}
let foo = container.resolve(FooProtocol.self)!
let bar = container.resolve(BarProtocol.self)!
return UIViewController(foo: foo, bar: bar)
}
}
then, somewhere in your app delegate you just need to call window?.rootViewController = Builder().makeViewController()
Thanks @yuriferretti-luizalabs for sharing your solution馃憤
I was able to use Assemblies and have AppDelegate maintain a strong reference to my MainAssembler. The problem I was having was that my Rx code was retaining the view controller.
@yuriferretti-luizalabs , it looks like you are using VIPER or VIP. Maybe double check you aren't retaining the view controller in the presenter or wireframe/router?
@jodyscho Thank for the help! I will check for retain cycles!