Q: Pass data between unrelated ViewControllers I am trying to implement a login screen that would put data into a view controller, the login view controller is called by overriding tabBarController didSelect method, just as follows:

Note that there is not any segue between the TabBarController and the ThirdViewController, because I override tabBarController as follows:
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {

// This delegate open the modal view after open the desired view.
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        if viewController is MyThirdViewController {
            if let loginPopupVC = tabBarController.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") {
                tabBarController.present(loginPopupVC, animated: true)
            }
        }
    }
}

Now, in my LoginViewController I parse a JSON in a struct (LoginResponse) with the data that is supposed to fill the ThirdViewController (name, surnames, sex, birth, and so on). I already do this with this snippet inside LoginViewController:
struct LoginResponse : Decodable {
    var name: String
    var surname: String
    var sex: String
    var birth: String
}

class LoginViewController: UIViewController, UITextFieldDelegate, XMLParserDelegate {

@IBAction func cancelLogin(_ sender: UIButton) {
        //LoginViewController will close and ThirdViewController will open
        dismiss(animated: true, completion: nil)
    }

@IBAction func makeLogin(_ sender: UIButton) {
        //LoginViewController brings data, closing itself and opening ThirdViewController
        self.updateUI()
        self.dismiss(animated: true, completion: nil)
    }

func updateUI() {
        do {
            let jsonDecoder = JSONDecoder()
            let myjson = "{\"name\": \"MyName\", \"surname\": \"MySurname\", \"sex\": \"Male\", \"birth\": \"1980-05-15\"}"
            let loginResult = try jsonDecoder.decode(LoginResponse.self, from: Data(myjson.utf8))
        }
        catch let jsonErr{
            print(jsonErr)
        }

    }
}

Now, I want to pass that data (inside loginResult) to ThirdViewController.
I guess that I cannot invoke ThirdViewController from LoginViewController, because TabBarController already did it, and that it is necessary if I choose pass data using Delegate method or NotificationCenter method.
I wanna know which of the passing-data options between ViewControllers would work better in this case, because usually that methods are explained in examples with two view controllers connected by a segue, but in my case, the flow of the screens is unusual. Thanks.

A: You can try something like this: 
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {

    // This delegate open the modal view after open the desired view.
    func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
        if viewController is MyThirdViewController {
            if let loginPopupVC = tabBarController.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") {
                loginPopupVC.delegate = tabBarController
                tabBarController.present(loginPopupVC, animated: true)
            }
        }
    }
}

For loginPopupVC:
struct LoginResponse : Decodable {
    var name: String
    var surname: String
    var sex: String
    var birth: String
}

class LoginViewController: UIViewController, UITextFieldDelegate, XMLParserDelegate {

    var delegate: loginDelegate?

    @IBAction func cancelLogin(_ sender: UIButton) {
        //LoginViewController will close and ThirdViewController will open
        dismiss(animated: true, completion: nil)
    }

    @IBAction func makeLogin(_ sender: UIButton) {
        //LoginViewController brings data, closing itself and opening ThirdViewController
        self.updateUI()
        self.dismiss(animated: true, completion: nil)
    }

    func updateUI() {
        do {
            let jsonDecoder = JSONDecoder()
            let myjson = "{\"name\": \"MyName\", \"surname\": \"MySurname\", \"sex\": \"Male\", \"birth\": \"1980-05-15\"}"
            let loginResult = try jsonDecoder.decode(LoginResponse.self, from: Data(myjson.utf8))
            // Pass data using delegate
            delegate?.handleLogin(with: loginResult)

        }
        catch let jsonErr{
            print(jsonErr)
        }

    }
}

And then for your tabBarController class:
protocol loginDelegate: class {
    func handleLogin(with object: LoginResponse)
}

class myTabBarController: UITabBarController, loginDelegate {

    // regular tabBarController lifecycle methods

    func handleLogin(with object: LoginResponse) {
        // do work with data
    }

}


A: Right. I would suggest declaring a variable in loginPopupVC to contain a reference to ThirdViewController, so in tabBar:didSelect after instantiating the loginVC you pass it a reference to ThirdVC, but before presenting the login. In Login, said variable is class level, so you can access it from the updateUI func. Now, declare a method or variable in ThirdView to contain the json and just pass it.
