New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
When and why to define Steps as computed property, static var, static func and let #85
Comments
TBH the Example project is just a demo, not an example of some kind of best practice. For me it was important to show that you can store the routes in variables, they can be dynamically updated and so on. I presonally create a protocol that I call typealias RoutingCompletionBlock = (_: RoutingResult) -> Void
protocol Wireframe: AnyObject {
var sharedWireframe: SharedWireframe { get }
var searchWireframe: SearchWireframe { get }
var moreWireframe: MoreWireframe { get }
var patientWireframe: PatientWireframe { get }
func showStudySelection(with context: StudyContext, completion: RoutingCompletionBlock?)
func showTeamSelect(with context: TeamSelectContext, completion: RoutingCompletionBlock?)
func showTeamDetail(with context: TeamDetailsListContext, completion: RoutingCompletionBlock?)
....
func showAlertsAttachment(with context: AlertsAttachmentFactory.Context, completion: RoutingCompletionBlock?)
} It may have some smaller wireframes inside for the smaller parts of the app. And then I implement all the |
Yeah I am definitely looking for a best practices approach as I would like to use this in a medium-scale production app. The protocol approach seems good but I have a couple questions on some of the specifics:
|
Hi @bennnjamin
final class DefaultWireframe: Wireframe {
private let router: Router ....
....
func showTeamDetail(with context: TeamDetailsListContext, completion: RoutingCompletionBlock?) {
let resultStep = StepAssembly(finder: ClassWithContextFinder(), factory: TeamDetailsListFactory(configuration: .init(payloadHolder: sessionPayloadHolder, networkManager: NetworkManager.shared, wireframe: self)))
.using(MainNavigationController.push())
.from(NavigationControllerStep())
.using(GeneralAction.presentModally(presentationStyle: nil))
.from(GeneralStep.current())
.assemble()
router.commitNavigation(to: Destination(to: resultStep, with: context), animated: true, completion: completion)
}
....
} |
public static func current<C>(windowProvider: WindowProvider = RouteComposerDefaults.shared.windowProvider) -> DestinationStep<UIViewController, C> {
DestinationStep(CurrentViewControllerStep(windowProvider: windowProvider))
} But you can use any other destination step and build longer chain. Why it can be needed? Like when you want to present something from some particular view controller. Not from just current. Let say you have 2 view controllers. One is a description of the hotel and another is a description of the room in this hotel. So when let say user receives a push notification that has a room id you want to push both view controllers into a navigation view controller. There it is usefull to use such chain. NB: Keep in mind those factories should use the same Lets look into the example with var squareScreen: DestinationStep<SquareViewController, Any?> {
StepAssembly(
finder: ClassFinder<SquareViewController, Any?>(),
factory: NilFactory())
.from(homeScreen)
.assemble()
}
var homeScreen: DestinationStep<UITabBarController, Any?> {
StepAssembly(
finder: ClassFinder<UITabBarController, Any?>(options: .current, startingPoint: .root),
factory: StoryboardFactory(name: "TabBar"))
.using(GeneralAction.replaceRoot(animationOptions: .transitionFlipFromLeft))
.from(GeneralStep.root())
.assemble()
} the code above basically represents next: var squareScreen: DestinationStep<SquareViewController, Any?> {
StepAssembly(
finder: ClassFinder<SquareViewController, Any?>(),
factory: NilFactory())
.from(StepAssembly(
finder: ClassFinder<UITabBarController, Any?>(options: .current, startingPoint: .root),
factory: StoryboardFactory(name: "TabBar"))
.using(GeneralAction.replaceRoot(animationOptions: .transitionFlipFromLeft))
.from(GeneralStep.root())
.assemble())
.assemble()
} that can be flattened something like this: I flattened it just for simplicity and to explain how flexible can be your chain configuration. There are multiple ways to write the same chain. var squareScreen: DestinationStep<SquareViewController, Any?> {
StepAssembly(
finder: ClassFinder<SquareViewController, Any?>(),
factory: NilFactory())
.from(SingleStep(finder: ClassFinder<UITabBarController, Any?>(options: .current, startingPoint: .root), factory: StoryboardFactory(name: "TabBar")))
.using(GeneralAction.replaceRoot(animationOptions: .transitionFlipFromLeft))
.from(GeneralStep.root())
.assemble()
}
Basically this gif explains what is happening there: I hope it expalins you why you may want a longer chain. I would suggest to read this article: |
Thanks, this is a really thorough explanation. I will need to do that exact example that you mentioned with showing a specific tab in a tab bar from anywhere in the app. I will work on it more this week and reach out if I have any more questions I like your approach a lot and will try to do something similar using the Wireframes. |
That article was actually how I found this project. I was looking at RxFlow and saw some stale github issues and your article completely convinced that this is the best navigation library for iOS. |
@bennnjamin Happy to help. Ill close this issue then. Feel free to reopen it or create a new one. Best of luck. |
I am new to this library and looking through the Example Project is a great place to start, it's very well documented. One thing that I have had trouble understanding and doesn't seem obvious is why Steps are defined in a variety of ways. Sometimes they are static vars/funcs, sometimes they are computed properties, and sometimes they are let constants.
What is your thinking in using these different approaches to defining routes? Why shouldn't every route just be
static let
so they can refer to each other if needed, and be accessible from every view controller?The text was updated successfully, but these errors were encountered: