QuickBirdEng / XCoordinator

🎌 Powerful navigation library for iOS based on the coordinator pattern
MIT License
2.26k stars 177 forks source link

Storyboard Support? #167

Closed brcbydr closed 4 years ago

brcbydr commented 4 years ago

Can I use XCoordinator with the storyboards? I couldn't see any example with storyboard and I have to decide if I can use XCoordinator. Thanks

pauljohanneskraft commented 4 years ago

Hey @brcbydr!

Sure, you can use XCoordinator with storyboards, however it depends on what features you use in these storyboards how much you can benefit from XCoordinator.

Segues

When using segues, you are bound to the prepareForSegue method to set up your destination view controller in your source view controller. This somewhat goes against the principle of the Coordinator Pattern. While it could be realized that these setups are delegated into a coordinator, it may be a lot harder to implement that than simply not using segues at all.

Creating view controllers from Storyboard

As you can see in our Example app, you can use XCoordinator with xibs quite easily. Since Storyboards are quite similar to xib-files, take a look at this documentation for more information on how to create view controllers from storyboards.

Let me know in case this does not fully answer your question, especially in which ways you would like to use XCoordinator in combination to Storyboards.

brcbydr commented 4 years ago

Hey @pauljohanneskraft, many thanks for your quick support. I didn't use segues like you mentioned. I instantiate viewcontroller using storyboard not nib:

override func prepareTransition(for route: AppRoute) -> NavigationTransition { switch route { case .firstLaunch: let vc: GuideScreenViewController = UIStoryboard(storyboard: .guideScreen).instantiateViewController() let vm = GuideScreenViewModelImpl(router: unownedRouter) vc.bind(to: vm) return .push(viewController) } }

I got that error "Value of type 'GuideScreenViewController' has no member 'bind'". Because viewcontroller has this error "Use of undeclared type 'BindableType'"

import UIKit import RxCocoa import RxSwift class GuideScreenViewController: BindableType { private let disposeBag = DisposeBag() var viewModel: GuideScreenViewModel!

func bindViewModel() {
    var page:GuidePage = Bundle.main.loadNibNamed("GuidePage", owner: self, options: nil)?.first as! GuidePage
    page.btnGotIt.rx.tap
        .bind(to: viewModel.input.gotItTrigger)
        .disposed(by: disposeBag)
}

}

I double checked all the implementation but couldn't find the reason. Please let me know if you got my error. Thanks again!

pauljohanneskraft commented 4 years ago

BindableType is defined as a protocol in the Example App itself - if you are using a MVVM approach, you can use it for your project as well, but it might not fit your architecture. If you use a MVC approach, you can simply get rid of the ViewModel completely, then you will also not need to bind a viewModel to your viewController.

brcbydr commented 4 years ago

I am using MVVM and I think I figure it out. I updated my storyboards. Every storyboard includes just one vc screen and it's name is same as the viewcontroller's name now. Using BindableStoryboardBased instead of BindableType.

protocol BindableStoryboardBased: AnyObject { associatedtype ViewModelType

var viewModel: ViewModelType! { get set }

func bindViewModel()

}

extension BindableStoryboardBased { static var storyboard: UIStoryboard { return UIStoryboard(name: String(describing: self), bundle: Bundle(for: self)) } }

extension BindableStoryboardBased where Self: UIViewController { func bind(to model: Self.ViewModelType) { viewModel = model loadViewIfNeeded() bindViewModel() } static func instantiate() -> Self { guard let vc = storyboard.instantiateInitialViewController() as? Self else { fatalError("The VC of \(sceneStoryboard) is not of class \(self)") } return vc } }

I think we can close the issue. I have another problem and will open new issue for that.