Can someBody Provide a complete solution for SceneCoordinator with UITabBarController in MVVM?

I am not able to create a fully stable Scene Coordinator with UITabBarController.

Can somebody help me with it?

Thanks

Hello hbasin3,

First of all, my advice for your next question is that first do a research on the forum’s entries and Internet and try to find out a solution on your own, this is the best way to learn, trust me. I understand that RxSwift is a little bit difficult for beginners but try first to have your own solution. After that make questions where you’re stuck and the probabilities to get an answer increase, the community is so kind here. Don’t get angry but your question looks like a command.

My approach resolve part of your question and it is not perfect, this is for UITabBarController with Scene Coordinator, MVVM is your homework.

  1. I download today the source code and upgrade the chapter 24 challenge’s Podfile to the following:

use_frameworks!
platform :ios, ‘12.0’

target ‘QuickTodo’ do
# core RxSwift
pod ‘RxSwift’, ‘~> 4.0’
pod ‘RxCocoa’, ‘~> 4.0’
pod ‘RxDataSources’, ‘~> 3.0’

# Community projects
pod ‘Action’
pod ‘NSObject+Rx’

# Realm database
pod ‘RealmSwift’
pod ‘RxRealm’
end

Then perform pod update from command line, then open the project, build it and upgrade everything. You must have a project without warnings. (I don’t like to have any warning on my projects).

  1. Create a new Swift file on Controllers folder named RootTabViewModel.swift and add the following source code:

    import Foundation

    struct RootTabViewModel {
    let sceneCoordinator: SceneCoordinatorType
    }

  2. Create a new Swift file on Controllers folder named RootTabBarController.swift and add the following source code:

    import UIKit

    class RootTabBarController: UITabBarController, BindableType {

    var viewModel: RootTabViewModel!

    override func viewDidLoad() {
    super.viewDidLoad()
    }

    func bindViewModel() {}
    }

  3. Add another case to Scene enum on Scene Swift file like this:

case mainTabBar(RootTabViewModel, TasksViewModel)

  1. Change the static function actualViewController in SceneCoordinator Swift file for:

    static func actualViewController(for viewController: UIViewController) -> UIViewController {

    if let navigationController = viewController as ? UINavigationController {

    return SceneCoordinator.actualViewController(for: navigationController.viewControllers.first!)

    } else if let tabBarController = viewController as ? UITabBarController,

    let selectedViewController = tabBarController.selectedViewController {

    return SceneCoordinator.actualViewController(for: selectedViewController)

    } else {

    return viewController

    }

    }

  2. Make some changes to Scene+ViewController Swift file:

Change the return type of the viewController() function from UIViewController to [UIViewController]

Then adjust every case return object from nc to [nc]

And add the following case:

case .mainTabBar(let rootTabViewModel, let tasksViewModel):
      var rootTabBarController = storyboard.instantiateViewController(withIdentifier: "RootTabBarController") as! RootTabBarController
      rootTabBarController.bindViewModel(to: rootTabViewModel)
      
      let tasksNavigationController = storyboard.instantiateViewController(withIdentifier: "Tasks") as! UINavigationController
      var tasksViewController = tasksNavigationController.viewControllers.first as! TasksViewController
      tasksViewController.bindViewModel(to: tasksViewModel)
      tasksNavigationController.tabBarItem = UITabBarItem(tabBarSystemItem: UITabBarItem.SystemItem.bookmarks, tag: 0)
      
      rootTabBarController.viewControllers = [tasksNavigationController]
      
      return [rootTabBarController]
      
    }

Compile the project and you get six errors on SceneCoordinator Swift file

  1. In SceneCoordinator Swift file fix all the errors:

The error message is:

Cannot convert value of type ‘[UIViewController]’ to expected argument type ‘UIViewController’

To fix every error change viewController for viewController[0]

  1. At this point the project must compile correctly but still cannot work, because we have to add the UITabBarController on our Main storyboard. Open your Main.storyboard file and add an UITabBarController.

From the Library, search for UITabBarController and drag and drop into the storyboard. Then select the item1 ViewController and hit delete, do the same for item2 ViewController. Select the Tab Bar Controller and select Show the Attributes inspector and select is Initial View Controller in the View Controller section, an arrow must appear on the left of the Tab Bar Controller. With the Tab Bar Controller still selected, select the Show the Identity inspector and set the following options:

In Custom Class section set Class as RootTabBarController.

And in Identity section set Storyboard ID as RootTabBarController.

If you compile your project it must be without errors be still cannot work as expected.

  1. Do the following changes in AppDelegate Swift file:

Remove the following lines:

let firstScene = Scene.tasks(tasksViewModel)
sceneCoordinator.transition(to: firstScene, type: .root)

And add the following lines:

let rootTabViewModel = RootTabViewModel(sceneCoordinator: sceneCoordinator)
let mainScene = Scene.mainTabBar(rootTabViewModel, tasksViewModel)
sceneCoordinator.transition(to: mainScene, type: .root)
  1. Compile and Run the project.

You must have a QuickTodo application without warnings and errors. And it resolves part of your question, a project with UITabBarController. The MVVM part in this example is in the middle of the process but it is a good starting point.

Credits: The awesome Ray Wenderlich forum community, sorry I don’t have a track of the forum’s entries.

Hope this helps you.

This topic was automatically closed after 166 days. New replies are no longer allowed.