skip to Main Content

Good night!
Can you tell me how can I write data from controller 2 to controller 1?
I have a coordinate at the main screen.

final class MenuCoffeLikeCoordinator: TabBarPresentableCoordinator {

var tabBarItem: UITabBarItem = {
    let title = "Меню"
    let image = UIImage(asset: Resources.Assets.TabBarItems.mainTabBar)
    let selectedImage = UIImage(asset: Resources.Assets.TabBarItems.mainTabBarSelected)
    let item = UITabBarItem(title: title, image: image, selectedImage: selectedImage)
    return item
}()

var navigationController: UINavigationController

init(navigationController: UINavigationController = UINavigationController()) {
    self.navigationController = navigationController
}

var didFinish: (() -> Void)?

func start() {
    self.navigationController.pushViewController(createMenuCoffeLikeFlow(), animated: true)
}

func stop() {}

func createMenuCoffeLikeFlow() { -> UIViewController {
    let menuController = MenuCoffeLikeAssembler.createModule()
    
    menuController.rx.didTapMapLayer.onNext {
        let controller = self.createCoffeeBarMap()
        self.navigationController.pushViewController(controller, animated: true)
    }
    
    return menuController
}
private func createCoffeeBarMap() -> UIViewController {
    let controller = CoffeeBarContainerAssembler.createModule()
    controller.obsRelay.subscribe(onNext: { event in
        self.navigationController.popViewController(animated: true)
    })
    return controller
}

}

In the createMenuCoffeLikeFlow function, I create the main screen, and when I click on the button, I go to screen 2 (createCoffeeBarMap)

Inside the function (createCoffeeBarMap), I subscribe to the PublishSubject, and when the data changes, I get a new text.
I need to write this text in the menuCoffeeControler which is in the createMenuCoffeLikeFlow function. How can i do this?

2

Answers


  1. Here’s how I would implement it using my Cause Logic Effect (CLE) architecture. With CLE you don’t need to implement a Coordinator because a reusable Coordinator class already exists in the library. This means less code for you to write.

    Unlike yours, this sample is complete and will compile. The only thing missing is the creation and layout of the views inside the view controllers.

    import Cause_Logic_Effect
    import RxCocoa
    import RxSwift
    import UIKit
    
    /// This function produces the view controller that is attached to your tab bar controller. I don't put the
    /// `UITabBarItem` in here. Instead I attach that when connecting to the tab bar controller.
    func menuCoffeLikeTab() -> UIViewController {
        // the `configure` function calls its closure inside the viewDidLoad method.
        let menuController = MenuController().configure { $0.connect() }
        let controller = UINavigationController(rootViewController: menuController)
        return controller
    }
    
    /// It depends on how you want to layout your view controllers on whether anything else goes in here. If you
    /// use storyboards, then add `@IBOutlet` before the views here. If you create your views programatically
    /// then add a `loadView()` override.
    final class MenuController: UIViewController {
        var mapLayerButton: UIButton!
        var textField: UITextField!
        let disposeBag = DisposeBag()
    }
    
    extension MenuController {
        func connect() {
            // This is the meat. The `coffeeBarResponse` observable pushes the
            // CoffeeBarController onto the navigation stack when approprate and
            // then emits any values produced by it. Notice how this looks alot like
            // a network call except you are querying the user instead of the server.
            let coffeeBarResponse = mapLayerButton.rx.tap
                .flatMapFirst(pushScene(on: navigationController!, animated: true) {
                    CoffeeBarController().scene { $0.connect() }
                })
                .share()
            // The pushScene function above will create a coordinator for the
            // CoffeeBarController. When needed, the coordinator will create the
            // view controller, call its `connect` and emit any values from that.
            // When the Observable completes, the coordinator will pop the view
            // controller off.
    
            coffeeBarResponse
                .bind(to: textField.rx.text)
                .disposed(by: disposeBag)
        }
    }
    
    final class CoffeeBarController: UIViewController {
        var saveButton: UIButton!
        var textField: UITextField!
    }
    
    extension CoffeeBarController {
        func connect() -> Observable<String> {
            // when the user taps the save button, this will emit whatever value is
            // in the text field and then complete the observable.
            saveButton.rx.tap
                .withLatestFrom(textField.rx.text.orEmpty)
                .take(1)
        }
    }
    

    Like I said above, this uses a reusable Coordinator class that is part of the library instead of you having to write your own all the time. This architecture will significantly reduce the amount of boilerplate code you have to write. Learn more at https://github.com/danielt1263/CLE-Architecture-Tools and join the RxSwift Slack to learn more about RxSwift in general.

    Login or Signup to reply.
  2. this is a typical scenario where DI comes to rescue. You have to have some kind of a shared container which will register and resolve dependencies. I use Dip https://github.com/AliSoftware/Dip.git and here is an example with your code. The idea is the following – you register closure in one VC and pass it to another.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search