FlowManager
public class FlowManager
Flow Manager is the core of our navigation system, it’s using this thay you will be able to make your navigation flow, it’s the important piece for you test your flows.
-
Flow Manager presentation style, as our flow start on top always, it’s a modal with navigation controller, by default is
fullScreen
, but with iOS 13 you can change this behaviour to have different style’s how to start / present your flow,- Variable:
- flowPresentationStyle: This is the variable that you should change / set before call
start()
the flow;
- flowPresentationStyle: This is the variable that you should change / set before call
Declaration
Swift
public var flowPresentationStyle: UIModalPresentationStyle
- Variable:
-
Flow Manager initialiser
Declaration
Swift
public init(navigation controller: UINavigationController?, container stack: ContainerFlowStack, setupInstance typeOfView: ViewIntanceFrom? = .nib, dismissed navigationFlow: (() -> ())? = nil)
Parameters
navigation
This is the basic and convenient custom UINavigationController instance if you want to have your custom one, to work is mandatory, so, if use this you need to set, when set, we will check if first view controller is there and set the navigation flow.
container
It’s the
ContainerFlowStack
instance, it’s where we will look for the registered View Controller types in order to resolve and show on the screen.setupInstance
It’s how will be our navigation, it’s a enum, if you don’t set we will assume that is nib view that you will be using.
dismissed
optional
- Closure optional that can tell you when this navigation controller was completely closed.
-
The method responsible to start the flow, we do not start automatically when instantiate our FlowManager, so you can start as soon you want.
Declaration
Swift
public func start(finishedLoad presenting: (() -> ())? = nil)
Parameters
finishedLoad
optional
- Convenience closure that will let you know when you finished the flow. -
This method is only intended when you want to have just a navigation controller but only when start decide which view controller will be the root of that navigation controller.
It’s basically the same behaviour as the initialiser that you need to pass the type of the view controller to be resolve, but with more options, in the scenario that only when you call start you want to check and validation which screen you want to have as the root, or even have a more generic way to show.
Using this, is mandatory to you have the view controller that you intend to use be registered in your
Container
so we can resolve.Usage Example:
flowManager.startWith(root: { () -> UIViewController.Type in // This is just a way to have some implementation that check the type // and will select the type according to the view controller, would be // your view controller type switch self.flowType { case .normal: return UIViewController.self case .withConfirmation: return UIViewController.self case .awareness: return UIViewController.self } }, resolved: { rootViewInstance in rootInstance.variable = "Any data that you want" })
Declaration
Swift
public func startWith<T: UIViewController>(root instanceType: () -> T.Type, resolved instance: (T) -> (), finishedLoad presenting: (() -> ())? = nil)
Parameters
root
The view controller type that you will have as
root
view controller for you navigation controller.resolved
Closure that will return the loaded instance reference for this loaded view, it’s good when you want to set some values or pass any parameter not using the custom resolve, you will have the right reference to pass value.
finishedLoad
optional
- Convenience closure that will let you know when you finished the flow. -
This method is only intended when you want to have just a navigation controller but only when start decide which view controller will be the root of that navigation controller, but without parameter to be passed during the instantiation.
It’s basically the same behaviour as the initialiser that you need to pass the type of the view controller to be resolve, but with more options, in the scenario that only when you call start you want to check and validation which screen you want to have as the root, or even have a more generic way to show.
Using this, is mandatory to you have the view controller that you intend to use be registered in your
Container
so we can resolve.Usage Example:
```` flowManager.startWith(root: { () -> UIViewController.Type in // This is just a way to have some implementation that check the type // and will select the type according to the view controller, would be // your view controller type switch self.flowType { case .normal: return UIViewController.self case .withConfirmation: return UIViewController.self case .awareness: return UIViewController.self } }) ````
Declaration
Swift
public func startWith<T: UIViewController>(root instanceType: () -> T.Type, finishedLoad presenting: (() -> ())? = nil)
Parameters
root
The view controller type that you will have as
root
view controller for you navigation controller.finishedLoad
optional
- Convenience closure that will let you know when you finished the flow. -
Method used to dismiss completely your flow.
- animated:
optional
- If you want to animated the dismiss of your flow default istrue
.completion:
optional
- Closure that you will receive an callback that you flow finished dismiss *(remember that if your instance is not strong you may not get this callback called.Note
It has
@discardableResult
because you can use other helper methods just after calling this method as we always return FlowManager instance.Usage Example:
// Basic call, withoud parameters navigationFlow?.dismissFlowController() // Calling passing parameters navigationFlow?.dismissFlowController(animated: true, completion: { // Finished dismiss flow })
Declaration
Swift
@discardableResult public func dismissFlowController(animated: Bool = true, completion: (() -> Void)? = nil) -> Self
- animated:
-
Method used to pass
Any
parameter back when finish flow, as soon you implement the closure to receive parameter back when flow finish as soon you pass using this method, the parameter will be sent, it’s not typed, it’sAny
so you need to cast if you want to identify and have typed parameter back, It’s recommended to use after call thedismissFlowController()
method.Usage Example:
// Basic call, withoud parameters navigationFlow?.dismissFlowController().finishFlowWith(parameter: "Finished")
Declaration
Swift
public func finishFlowWith(parameter data: Any)
Parameters
parameter
Any value that you want to pass back when flow finish.
-
This should be called only when you instantiate your FlowManager as it’s intended only to pass parameter back that you perhaps want like a response after finish
Note
It has
@discardableResult
because you can use other helper methods just after calling this method as we always return FlowManager instance.Usage Example:
// Here we set after intantiate the `Flow Manager` that when dismiss // we want to `listen` any paramter that will be sent back FlowManager(root: view, container: navigationStack).dismissedFlowWith { [weak self] closeAll in // Using this parameter for the situation that we want to dismiss both navigation from the top one if (closeAll as? Bool) == true { self?.navigationFlow?.dismissFlowController() } }.start() // And for use, to pass back we just need when dismiss call the method `.finishFlowWith(parameter: )` navigationFlow?.dismissFlowController().finishFlowWith(parameter: true)
Declaration
Swift
@discardableResult public func dismissedFlowWith(parameter invoker: @escaping (Any) -> ()) -> Self
Parameters
parameter
Any value that you want to pass back when flow finish.
-
This is intended to you know when you dismiss your presented modal view controller and you want to know if already finished close the presented one.
Note
It has
@discardableResult
because you can use other helper methods just after calling this method as we always return FlowManager instance.Usage Example:
navigationFlow?.goNextAsModal().dismissedModal(callback: { [unowned self] in debugPrint("Finished close modal view") self.getSomeDataFromClosedModal() })
Declaration
Swift
@discardableResult public func dismissedModal(callback invoker: @escaping () -> ()) -> Self
Parameters
parameter
Any value that you want to pass back when flow finish.
-
Helper method that you can get the instance reference to the
UINavigationController
in case you do not provided a custom oneDeclaration
Swift
public func managerNavigation() -> UINavigationController?
-
Helper method that give you back the container flow stack reference
Declaration
Swift
public func container() -> ContainerFlowStack?
-
Helper method that will print your stack, so you can have a visual understand how your stack is right now
Declaration
Swift
@discardableResult public func stackState() -> String
-
This is the method that we will use in order to send parameter when resolve our instance Remember that when declare the parameter data that you want to be resolved need to be inside Tuple, as for swift when resolve everything need to have a type, with this we make sure that always have type and the values are inside
Usage Example:
// Basic implementation navigationFlow?.goNextWith(screen: ParameterFirstViewController.self, parameters: { () -> ((String, Int)) in return ("Felipe Garcia", 232) }) // Using the parameters available navigationFlow?.goNextWith(screen: ParameterFirstViewController.self, parameters: { () -> ((String, Int)) in return ("Felipe Garcia", 232) }, resolve: .nib, resolved: { resolveView in // resolve view }) // Basic implementation with custom Identifier navigationFlow?.goNextWith(screen: ParameterFirstViewController.self, customIdentifier: "ChoseThisScreen", parameters: { () -> ((String, Int)) in return ("Felipe Garcia", 232) })
Declaration
Swift
public func goNextWith<T: UIViewController, Resolver>(screen view: T.Type, customIdentifier: String? = nil, parameters data: @escaping () -> ((Resolver)), resolve asType: ViewIntanceFrom = .nib, resolved instance: ((T) -> ())? = nil)
Parameters
screen
The type of the view controller that you want to next.
customIdentifier
optional
- String that is custom identifier to identify particular viewparamer
Closure that expect a
type
that will be used when resolve this screen that you are calling.resolve
optional
- How the view for this screen will be loaded, the default one is.nib
.resolved
optional
- Convenience closure that will return the loaded instance reference for this loaded view, it’s good when you want to set some values or pass any parameter not using the custom resolve, you will have the right reference to pass value. -
Method responsible to navigate to the next screen
Usage Example:
navigationFlow?.goNext(screen: SecondViewController.self, resolve: .nib, resolved: { resolveViewInstance in resolveViewInstance.nameForTitle = "Setting value on the next view" }) // Basic implementation with custom Identifier navigationFlow?.goNext(screen: SecondViewController.self, customIdentifier: "ChoseThisScreen"," resolve: .nib, resolved: { resolveViewInstance in resolveViewInstance.nameForTitle = "Setting value on the next view" })
Declaration
Swift
public func goNext<T: UIViewController>(screen view: T.Type, customIdentifier: String? = nil, resolve asType: ViewIntanceFrom = .nib, resolved instance: ((T) -> ())? = nil)
Parameters
screen
The type of the screen that you want to go, need to be registered in your container flow stack.
customIdentifier
optional
- String that is custom identifier to identify particular viewresolve
optional
- How the view for this screen will be loaded, the default one is.nib
.resolved
optional
- Convenience closure that will return the loaded instance reference for this loaded view, it’s good when you want to set some values or pass any parameter not using the custom resolve, you will have the right reference to pass value. -
Method responsible to navigate to the next screen automatically resolve and go to the next view according to the order that you declared in your ContainerFlowStack, if no item found will just not navigation we do not throw any error
Usage Example:
// Without using any parameter - Indicated to the automatically navigation navigationFlow?.goNext() // Using the parameters available navigationFlow?.goNext(resolve: .nib, resolved: { resolveViewInstance in resolveViewInstance.nameForTitle = "Setting value on the next view" })
Declaration
Swift
public func goNext<T: UIViewController>(resolve asType: ViewIntanceFrom = .nib, customIdentifier: String? = nil, resolved instance: ((T) -> ())? = nil)
Parameters
resolve
optional
- How the view for this screen will be loaded, the default one is.nib
.customIdentifier
optional
- String that is custom identifier to identify particular viewresolved
optional
- Convenience closure that will return the loaded instance reference for this loaded view, it’s good when you want to set some values or pass any parameter not using the custom resolve, you will have the right reference to pass value. -
Method responsible to navigate to the next screen using
Modal Presentation
, this method can automatically resolve too, if you do not need any of the parameters argument just call the method without implement any of the arguments and will automatically resolve according to you container stack declared.Note
It has
@discardableResult
because you can use other helper methods just after calling this method as we always return FlowManager instance.Usage Example:
// Simple implementation indicated for automatically navigation navigationFlow?.goNextAsModal() // Full implementation using all parameters navigationFlow?.goNextAsModal(screen: SecondViewController.self, resolve: .nib, animated: true, resolved: { resolveViewInstance in resolveViewInstance.nameForTitle = "Setting value on the next view" }, completion: { // Finished presenting this modal. }) // Implementation specifying custom identifier navigationFlow?.goNextAsModal(screen: SecondViewController.self, customIdentifier: "MyCustomViewToLoad", resolve: .nib, animated: true, resolved: { resolveViewInstance in resolveViewInstance.nameForTitle = "Setting value on the next view" }, completion: { // Finished presenting this modal. })
Declaration
Swift
@discardableResult public func goNextAsModal<T: UIViewController>(screen view: T.Type? = nil, customIdentifier: String? = nil, resolve asType: ViewIntanceFrom = .nib, animated modalShow: Bool = true, resolved instance: ((T) -> ())? = nil, presentation style: UIModalPresentationStyle = .fullScreen, completion: (() -> Void)? = nil) -> Self
Parameters
screen
optional
- The type of the screen that you want to go, need to be registered in your container flow stack.customIdentifier
optional
- String that is custom identifier to identify particular viewresolve
optional
- How the view for this screen will be loaded, the default one is.nib
.animated
optional
- If you want to show the modal view presentation animated or not, default is animated.resolved
optional
- Convenience closure that will return the loaded instance reference for this loaded view, it’s good when you want to set some values or pass any parameter not using the custom resolve, you will have the right reference to pass value.presentation
optional
- How the modal will be presented, as iOS 13 is not defaultfullScreen
anymore, here the default will befullScreen
.completion
optional
- Called when the modal view is presented, so you know when success show. -
goNextAsModalWith(parameters:screen:customIdentifier:resolve:animated:resolved:presentation:completion:)
Method responsible to navigate to the next screen using
Modal Presentation
, this method can automatically resolve too, if you do not need any of the parameters argument just call the method without implement any of the arguments and will automatically resolve according to you container stack declared.Note
It has
@discardableResult
because you can use other helper methods just after calling this method as we always return FlowManager instance. You still have all the other method like the modal presentation without parameter.Usage Example:
// Simple implementation indicated for automatically navigation navigationFlow?.goNextAsModalWith(parameters: { return ("Any Data") }, screen: SecondViewController.self }) // Simple implementation with identifier navigationFlow?.goNextAsModalWith(parameters: { return ("Any Data") }, screen: SecondViewController.self, customIdentifier: "MyCustomViewToLoad" })
Declaration
Swift
@discardableResult public func goNextAsModalWith<T: UIViewController, Resolver>(parameters data: @escaping () -> ((Resolver)), screen view: T.Type, customIdentifier: String? = nil, resolve asType: ViewIntanceFrom = .nib, animated modalShow: Bool = true, resolved instance: ((T) -> ())? = nil, presentation style: UIModalPresentationStyle = .fullScreen, completion: (() -> Void)? = nil) -> Self
Parameters
paramer
Closure that expect a
type
that will be used when resolve this screen that you are calling.screen
The type of the screen that you want to go, need to be registered in your container flow stack.
customIdentifier
optional
- String that is custom identifier to identify particular viewresolve
optional
- How the view for this screen will be loaded, the default one is.nib
.animated
optional
- If you want to show the modal view presentation animated or not, default is animated.resolved
optional
- Convenience closure that will return the loaded instance reference for this loaded view, it’s good when you want to set some values or pass any parameter not using the custom resolve, you will have the right reference to pass value.presentation
optional
- How the modal will be presented, as iOS 13 is not defaultfullScreen
anymore, here the default will befullScreen
.completion
optional
- Called when the modal view is presented, so you know when success show. -
This is used to get back when you are navigating using flow manager, with this you can easy get back just one view or get back to the root view from you navigation controller stack, it’s even possible pass say to which screen you want to get back passing the type.
Note
It has
@discardableResult
because you can use other helper methods just after calling this method as we always return FlowManager instance.Usage Example:
// Basic pop, just get back one screen animated navigationFlow?.getBack() // Specifying what type of the pop and the view that you want to get back navigationFlow?.getBack(pop: .pop(animated: true), screen: { viewToGo in viewToGo(FirstViewController.self) })
Declaration
Swift
@discardableResult public func getBack<T: UIViewController>(pop withStyle: NavigationPopStyle = .pop(animated: true), screen view: (((T.Type) -> ()) -> ())? = nil) -> Self
Parameters
pop
optional
- Type of the pop action that you want to do, check NavigationPopStyle to see all possibilities, default is back one animated.screen
optional
- The type of the screen that you want to go, need to be registered in your container flow stack.
-
Flow Manager convenience initialiser for when you want to resolve the root view controller from your navigation controller receiving parameters.
1 - When we are already in one storyboard, and we want to load another viewcontroller that is inside this storyboard you can resolve using
rootInstance
to resolve and will be set to as your root view controller inside your navigation controller.Example: We have setup our Storyboard, and we embed in on our view controllers our UINavigationController Them as we want to use the Flow Manager to handle our navigation, we need to get the reference to our view controller and set as our
custom navigation
, but we need to know who is the root of this navigation, so for this we pass theroot
type of the view.2 - When you are loading a completely new storyboard, as you will need to resolve your first / root view controller using the reference from the storyboar as it’s not loaded yet, so for this scenario you only pass the type of the first one
root
that will be resolved so we hande this resolution for you, otherwise will load with a black screen your navigation.Declaration
Swift
public convenience init<T: UIViewController, Resolver>(root instanceType: T.Type, container stack: ContainerFlowStack, parameters data: @escaping () -> ((Resolver)), withCustom navigation: UINavigationController? = nil, setupInstance type: ViewIntanceFrom = .nib, dismissed navigationFlow: (() -> ())? = nil)
Parameters
root
The view controller type that you will have as
root
view controller for you navigation controller.container
It’s the
ContainerFlowStack
instance, it’s where we will look for the registered View Controller types in order to resolve and show on the screen.parameters
Closure that expect the parameter that you want to be passed to when we resolve, need to follow the same order and type of the register that is expecting this parameter(s).
withCustom
optional
- Custom UINavigationController it’s optional, if not we will use the default one from UIKit.setupInstance
optional
- It’s how will be our navigation, it’s a enum, if you don’t set we will assume that is nib view that you will be using.dismissed
optional
- Closure optional that can tell you when this navigation controller was completely closed. -
Flow Manager convenience initialiser
1 - When we are already in one storyboard, and we want to load another viewcontroller that is inside this storyboard you can resolve using
rootInstance
to resolve and will be set to as your root view controller inside your navigation controller.Example: We have setup our Storyboard, and we embed in on our view controllers our UINavigationController Them as we want to use the Flow Manager to handle our navigation, we need to get the reference to our view controller and set as our
custom navigation
, but we need to know who is the root of this navigation, so for this we pass theroot
type of the view.2 - When you are loading a completely new storyboard, as you will need to resolve your first / root view controller using the reference from the storyboar as it’s not loaded yet, so for this scenario you only pass the type of the first one
root
that will be resolved so we hande this resolution for you, otherwise will load with a black screen your navigation.Declaration
Swift
public convenience init<T: UIViewController>(root instanceType: T.Type, container stack: ContainerFlowStack, withCustom navigation: UINavigationController? = nil, setupInstance type: ViewIntanceFrom = .nib, dismissed navigationFlow: (() -> ())? = nil)
Parameters
root
The view controller type that you will have as
root
view controller for you navigation controller.container
It’s the
ContainerFlowStack
instance, it’s where we will look for the registered View Controller types in order to resolve and show on the screen.withCustom
optional
- Custom UINavigationController it’s optional, if not we will use the default one from UIKit.setupInstance
optional
- It’s how will be our navigation, it’s a enum, if you don’t set we will assume that is nib view that you will be using.dismissed
optional
- Closure optional that can tell you when this navigation controller was completely closed. -
This is intend to when you are sending parameter but you are using Storyboard as navigation as when it’s the Storyboard the one responsible for resolve your instance, the best that we can provide is if you implement this method in our class so as soon was instantiated we will send and you will be able to receive parameter from the caller.
Usage Example:
// Send the data to the next view controller when using Storyboard navigationFlow?.goNextWith(screen: AutomaticallyFirstViewController.self, parameters: { ("Felipe", 3123.232, "Florencio", 31) }) // Implemented in the View Controller that you intend to receive the data that will be sent. navigationFlow?.dataFromPreviousController(data: { (arguments: (String, Double, String, Int)) in let (first, second, third, fourth) = arguments debugPrint("First parameter: \(first) - Storyboard Automatically Navigation") debugPrint("Second parameter: \(second) - Storyboard Automatically Navigation") debugPrint("Third parameter: \(third) - Storyboard Automatically Navigation") debugPrint("Fourth parameter: \(fourth) - Storyboard Automatically Navigation") })
Declaration
Swift
public func dataFromPreviousController<Parameter>(data parameter: (Parameter) -> ())
Parameters
data
Closure that will receive the parameter, you need to declare the types the same order that you are expecting.