lngyeen / MySurveyChallenge

0 stars 0 forks source link

[Question] More complex navigation application #36

Closed blyscuit closed 4 months ago

blyscuit commented 4 months ago

Issue

How would you design an application with more complex navigation?

Examples:

lngyeen commented 4 months ago

In UIKit:

To be reusable we can implement a Factory pattern so when we push/modal a new UIViewController we can use that Factory to init and setup data for new UIViewController before pushing. In my current project i apply a new pattern like this:

protocol BindableType: AnyObject {
    associatedtype ViewModelType
    var viewModel: ViewModelType! { get set }
    func bindViewModel()
}

extension BindableType where Self: UIViewController {
    func bindViewModel(to model: Self.ViewModelType, nibLoaded: Bool = false) {
        viewModel = model
        if !nibLoaded {
            loadViewIfNeeded()
        }
        bindViewModel()
    }
}

extension BindableType where Self: UIView {
    func bindViewModel(to model: Self.ViewModelType) {
        viewModel = model
        bindViewModel()
    }
}

import Foundation

struct Treatments: Flow {
    let scene: Scene
    init(scene: TreatmentsScene) {
        self.scene = scene
    }
}

enum TreatmentsScene: Scene {
    case treatmentPlanDetails(TreatmentPlanDetailsViewModel)
    case treatmentPeriodDetails(TreatmentPeriodDetailsViewModel)
    case recommendationDetails(RecommendationDetailsViewModel)
}

extension TreatmentsScene {
    func viewController() -> UIViewController {
        switch self {
        case let .treatmentPlanDetails(viewModel):
            let vc = TreatmentPlanDetailsViewController()
            vc.bindViewModel(to: viewModel)
            return vc

        case let .treatmentPeriodDetails(viewModel):
            let vc = TreatmentPeriodDetailsViewController()
            vc.bindViewModel(to: viewModel)
            return vc

        case let .recommendationDetails(viewModel):
            let vc = RecommendationDetailsViewController()
            vc.bindViewModel(to: viewModel)
            return vc
        }
    }
}

and then push/modal new screen like this:

let sceneCoordinator = SceneCoordinator(navigationController: navigationController)
let vm = ViewModel()
sceneCoordinator.transitionTo(flow: Treatments(scene: .treatmentPlanDetails(vm)),
                                      type: .push(hidesBottomBarWhenPushed: true))

contains UINavigationController.

In SwiftUI: To be honest, I haven't studied SwiftUI very deeply, so I'll answer these parts based on my limited knowledge. I will try to update in the near future :)