From 99b21dc83f222bbd05b767c71f3ff8eb7a0c2798 Mon Sep 17 00:00:00 2001 From: Andrew Gold Date: Mon, 28 Oct 2019 15:36:49 -0700 Subject: [PATCH] Explicitly type view controller injection --- CBInjection.xcodeproj/project.pbxproj | 4 ++ .../UINavigationController+Injectables.swift | 8 ++-- .../UIViewController+Injectables.swift | 11 ++--- CBInjection/Models/InjectionKey.swift | 7 ++- .../Models/ViewControllerInjectionKey.swift | 48 +++++++++++++++++++ 5 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 CBInjection/Models/ViewControllerInjectionKey.swift diff --git a/CBInjection.xcodeproj/project.pbxproj b/CBInjection.xcodeproj/project.pbxproj index cd16c9d..280965f 100644 --- a/CBInjection.xcodeproj/project.pbxproj +++ b/CBInjection.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + D30B80852367A32000D3D508 /* ViewControllerInjectionKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = D30B80842367A32000D3D508 /* ViewControllerInjectionKey.swift */; }; E74DE55C22333E83008CC5EE /* CBInjection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E74DE55222333E83008CC5EE /* CBInjection.framework */; }; E74DE56122333E83008CC5EE /* DependenciesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E74DE56022333E83008CC5EE /* DependenciesTests.swift */; }; E74DE57D22333F9D008CC5EE /* InjectionParameterName.swift in Sources */ = {isa = PBXBuildFile; fileRef = E74DE56D22333F9D008CC5EE /* InjectionParameterName.swift */; }; @@ -31,6 +32,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + D30B80842367A32000D3D508 /* ViewControllerInjectionKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerInjectionKey.swift; sourceTree = ""; }; E74DE55222333E83008CC5EE /* CBInjection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CBInjection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; E74DE55B22333E83008CC5EE /* CBInjectionTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CBInjectionTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E74DE56022333E83008CC5EE /* DependenciesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependenciesTests.swift; sourceTree = ""; }; @@ -112,6 +114,7 @@ E74DE56D22333F9D008CC5EE /* InjectionParameterName.swift */, E74DE56E22333F9D008CC5EE /* InjectionKey.swift */, E74DE56F22333F9D008CC5EE /* InjectionScope.swift */, + D30B80842367A32000D3D508 /* ViewControllerInjectionKey.swift */, ); path = Models; sourceTree = ""; @@ -261,6 +264,7 @@ E74DE58322333F9D008CC5EE /* UINavigationController+Injectables.swift in Sources */, E74DE57D22333F9D008CC5EE /* InjectionParameterName.swift in Sources */, E74DE57F22333F9D008CC5EE /* InjectionScope.swift in Sources */, + D30B80852367A32000D3D508 /* ViewControllerInjectionKey.swift in Sources */, E74DE58722333F9D008CC5EE /* Dependencies.swift in Sources */, E74DE58422333F9D008CC5EE /* UIViewController+Injectables.swift in Sources */, E74DE57E22333F9D008CC5EE /* InjectionKey.swift in Sources */, diff --git a/CBInjection/Extensions/UINavigationController+Injectables.swift b/CBInjection/Extensions/UINavigationController+Injectables.swift index dc69dbc..5cfc572 100644 --- a/CBInjection/Extensions/UINavigationController+Injectables.swift +++ b/CBInjection/Extensions/UINavigationController+Injectables.swift @@ -6,7 +6,7 @@ public extension UINavigationController { /// Initialize the navigation controller with an injected root view controller /// /// - Parameter rootViewControllerKey: the injection key for the root view controller - convenience init(rootViewControllerKey: InjectionKey) { + convenience init(rootViewControllerKey: ViewControllerInjectionKey) { guard let viewController = try? Dependencies.shared.provide(rootViewControllerKey) else { fatalError("View controller not found") } @@ -22,7 +22,7 @@ public extension UINavigationController { /// /// - Returns: Instance of ViewController generated using provided injection key @discardableResult - func pushViewController(_ key: InjectionKey, animated: Bool) -> T? { + func pushViewController(_ key: ViewControllerInjectionKey, animated: Bool) -> UIViewController? { guard let viewController = try? Dependencies.shared.provide(key) else { assertionFailure("Unable to push view controller for key \(key)") return nil @@ -38,7 +38,7 @@ public extension UINavigationController { /// - Parameters: /// - keys: Injection keys for the view controllers /// - animated: true if the transition should be animated - func setViewControllers(_ keys: [InjectionKey], animated: Bool) { + func setViewControllers(_ keys: [ViewControllerInjectionKey], animated: Bool) { let viewControllers = keys.compactMap { key -> UIViewController? in guard let viewController: UIViewController = try? Dependencies.shared.provide(key) else { assertionFailure("Unable to push view controller for key \(key)") @@ -58,7 +58,7 @@ public extension UINavigationController { /// - animated: true if the transition should be animated /// /// - Returns: Instance of ViewController generated using provided injection key - func setRootViewController(_ key: InjectionKey, animated: Bool) -> T? { + func setRootViewController(_ key: ViewControllerInjectionKey, animated: Bool) -> UIViewController? { guard let viewController = try? Dependencies.shared.provide(key) else { assertionFailure("Unable to push view controller for key \(key)") return nil diff --git a/CBInjection/Extensions/UIViewController+Injectables.swift b/CBInjection/Extensions/UIViewController+Injectables.swift index d41a741..f5b23fc 100644 --- a/CBInjection/Extensions/UIViewController+Injectables.swift +++ b/CBInjection/Extensions/UIViewController+Injectables.swift @@ -13,18 +13,17 @@ public extension UIViewController { /// /// - Returns: Instance of ViewController generated using provided injection key @discardableResult - func present( - _ key: InjectionKey, + func present( + _ key: ViewControllerInjectionKey, animated: Bool, - modalPresentationStyle: UIModalPresentationStyle = .fullScreen, completion: (() -> Void)? = nil - ) -> T? { + ) -> UIViewController? { guard let viewController = try? Dependencies.shared.provide(key) else { assertionFailure("Unable to present view controller for key \(key)") return nil } - viewController.modalPresentationStyle = modalPresentationStyle + viewController.modalPresentationStyle = key.modalPresentationStyle present(viewController, animated: animated, completion: completion) @@ -37,7 +36,7 @@ public extension UIViewController { /// - key: Key used to create view controller /// /// - Returns: Instance of ViewController generated using provided injection key - func addChild(_ key: InjectionKey) -> T? { + func addChild(_ key: ViewControllerInjectionKey) -> UIViewController? { guard let viewController = try? Dependencies.shared.provide(key) else { assertionFailure("Unable to present view controller for key \(key)") return nil diff --git a/CBInjection/Models/InjectionKey.swift b/CBInjection/Models/InjectionKey.swift index 5876514..6c1593f 100644 --- a/CBInjection/Models/InjectionKey.swift +++ b/CBInjection/Models/InjectionKey.swift @@ -3,7 +3,7 @@ import Foundation /// Represents and injection key used indentify a dependency. -public final class InjectionKey: InjectionKeys { +public class InjectionKey: InjectionKeys { /// Injection which contains the code for resolving a dependency let injection: DependencyInjection? @@ -32,14 +32,13 @@ public final class InjectionKey: InjectionKeys { } /// Closure-based constructor - public init( + public required init( uuid: String = NSUUID().uuidString, scope: InjectionScope, - parameters: [InjectionParameterName: Any] = [:], closure: @escaping ((Dependencies) throws -> T) ) { self.scope = scope - self.parameters = parameters + self.parameters = [:] self.closure = closure injection = nil super.init(uuid: uuid) diff --git a/CBInjection/Models/ViewControllerInjectionKey.swift b/CBInjection/Models/ViewControllerInjectionKey.swift new file mode 100644 index 0000000..04971c3 --- /dev/null +++ b/CBInjection/Models/ViewControllerInjectionKey.swift @@ -0,0 +1,48 @@ +// Copyright (c) 2017-2019 Coinbase Inc. See LICENSE + +import UIKit + +public class ViewControllerInjectionKey: InjectionKey { + /// View controller modal presentation style + let modalPresentationStyle: UIModalPresentationStyle + + public required init( + uuid: String = NSUUID().uuidString, + scope: InjectionScope, + modalPresentationStyle: UIModalPresentationStyle = .fullScreen, + closure: @escaping (Dependencies) throws -> UIViewController + ) { + self.modalPresentationStyle = modalPresentationStyle + super.init(uuid: uuid, scope: scope, closure: closure) + } + + public required init( + uuid: String = NSUUID().uuidString, + using injectionObjectType: DependencyInjection.Type, + scope: InjectionScope, + parameters: [InjectionParameterName: Any] = [:], + modalPresentationStyle: UIModalPresentationStyle = .fullScreen + ) { + self.modalPresentationStyle = modalPresentationStyle + super.init(uuid: uuid, using: injectionObjectType, scope: scope, parameters: parameters) + } + + @available(*, unavailable) + public required init( + uuid: String = NSUUID().uuidString, + scope: InjectionScope, + closure: @escaping ((Dependencies) throws -> UIViewController) + ) { + fatalError("init(uuid:scope:closure:) has not been implemented") + } + + @available(*, unavailable) + public required init( + uuid: String = NSUUID().uuidString, + using injectionObjectType: DependencyInjection.Type, + scope: InjectionScope, + parameters: [InjectionParameterName : Any] = [:] + ) { + fatalError("init(uuid:using:scope:parameters:) has not been implemented") + } +}