0

My scenario, I am having Tabbar with three viewcontroller. Here, tabbar first viewcontroller I am showing tableview. If I click the tableview cell it will show one popup present model viewcontroller. In this present popup viewcontroller I am maintaining two bar button cancel and done. If I click done It will dismiss and show tabbar main view controller. While dismiss time I need to pass some values with button flag from present popup view controller to tabbar main viewcontroller.

Here, below my dismiss popup pass viewcontroller code (VC 2)

@IBAction func apply_click(_ sender: Any) {
        print("Dimiss Filter")
        dismiss(animated: true, completion: {

            if let navView = self.tabBar?.viewControllers?[0] as? UINavigationController {
                if let secondTab = navView.viewControllers[0] as? HomeViewController {
                    secondTab.selectedIndexFromFirstTab = self.selectedIndex
                    //secondTab.item = self.item
                    secondTab.tfData = "YES"
                }
            }
            self.tabBar?.selectedIndex = 0
        })
    }

Here, Tabbar main view controller code (receiving values) (VC 1)

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        print("SELECTED INDEX:\(selectedIndexFromFirstTab)")
        print("RESPONSE:\(tfData)")
    }

I am not receiving values, how to solve this issue.

devmikle
  • 105
  • 2
  • 11

3 Answers3

2

You can achieve it multiple ways. Using blocks/closures, protocols or if you are using RxSwift than using controlled property or using controlled events. Because I can't demonstrate everything here am gonna write protocol

Using Protocol

Step 1:

Declare a protocol in your modal view controller

@objc protocol ModalViewControllerProtocol {
    func dismiss(with data: String)
}

Step 2:

ViewController that presents this ModalViewController make it to confirm the protocol

extension HomeViewController: ModalViewControllerProtocol {
    func dismiss(with data: String) {
        //use the data here
        self.presentedViewController?.dismiss(animated: true, completion: nil)
    }
}

Step 3:

Declare a variable to hold delegate reference in ModalViewController

weak var delegate: ModalViewControllerProtocol? = nil

Step 4:

In your ViewCOntroller that presents the modalViewController pass self as a delegate to ModalViewController before presenting

    let modalVC = //...
    modalVC.delegate = self
    self.present(modalVC, animated: true, completion: nil)

Finally in IBAction of ModalViewController simply call

@IBAction func apply_click(_ sender: Any) {
    self.delegate?.dismiss(with: "your_data_here")
}

Using Block/Closure

Step 1:

In your modal ViewController declare a property that accepts a block/closure

var completionBlock: (((String) -> ()))? = nil

Step 2:

In your ViewController that presents this ModalViewController, pass a block before presenting it

    let modalVC = //...
    modalVC.completionBlock = {(data) in
        debugPrint(data)
        self.presentedViewController?.dismiss(animated: true, completion: nil)
    }
    self.present(modalVC, animated: true, completion: nil)

Step 3:

Finally in your ModalViewController IBAction simply execute the block passed

    if let block = completionBlock {
        block("your data here")
    }

Hope it helps

Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
  • Thank you. Could you please update which is tabbar main view controller and which one is poup view controller. based on my title, it will make clea @Sandeep Bhandari – devmikle Feb 20 '19 at 07:53
  • 1
    @devmikle: I have specified that viewController is the view controller in tab bar where as modalViewController is the view controller that you are planning to present modally – Sandeep Bhandari Feb 20 '19 at 07:54
  • Sorry. I can't able to understand. If you don't mind please make very clear @Sandeep Bhandari – devmikle Feb 20 '19 at 07:56
  • 1
    @devmikle : It is a generic answer you can get the idea from it apply it your scenario – Sandeep Bhandari Feb 20 '19 at 08:01
  • @SandeepBhandari Perfect Answer! – Harjot Singh Feb 20 '19 at 08:06
  • But my question is child to parent data pass. @Sandeep Bhandari – devmikle Feb 20 '19 at 08:09
  • @Sandeep Bhandari What if i want to pass the block to another viewcontroller which i am not pushing from this viewcontroller? how can we achieve that? I know with delegate. – Harjot Singh Feb 20 '19 at 08:10
  • 1
    @harjot-singh: In anyway if you can get the reference to the view controller that is being presented, passing block should be straight forward :) – Sandeep Bhandari Feb 20 '19 at 08:24
  • @Sandeep Bhandari Can you please do it with example in the edit? i am not able to think about it what is in your mind? – Harjot Singh Feb 20 '19 at 08:28
  • @harjot-singh: It will be inappropriate to add anything like here as its out of context to this question, please consider adding a new question that will give more n clear context of your question and also will open the question to bigger audience and who knows someone with better understanding might provide better answer as well :) – Sandeep Bhandari Feb 20 '19 at 08:31
  • @Sandeep Bhandari, please answer asap. https://stackoverflow.com/questions/54782250/how-can-we-pass-the-closures-to-any-viewcontroller-in-the-app-flow – Harjot Singh Feb 20 '19 at 08:53
2

From my previous answer you need to make few changes to existing code if you want to pass values from your child view to main tab bar controller.

For that first of all you need to declare a method into your main TabBarViewController

func tabPressedWithIndex(index: Int, valueToPass: String) {
    print("selected Index: \(index)")
    print("Value from user: \(valueToPass)")
}

Now you need to pass that tab bar controller to your detail view with didSelectRowAt method and it will look like:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    let vc = self.storyboard?.instantiateViewController(withIdentifier: "DetailViewController") as! DetailViewController
    vc.selectedIndex = indexPath.row
    vc.tabBar = self.tabBarController as? TabBarViewController  // Here you need to assign tab bar controller.
    self.present(vc, animated: true, completion: nil)
}

Now next thing is when you click on dismiss button from detail view controller you need to add one line below self.tabBar?.selectedIndex = 1:

self.tabBar?.tabPressedWithIndex(index: 1, valueToPass: self.userTF.text!)

Now this will pass the values to main tab bar controller and method tabPressedWithIndex will call and print your data in your main tab.

Check out demo project for more info.

Dharmesh Kheni
  • 71,228
  • 33
  • 160
  • 165
1

This is the solution

self.dismiss(animated: true) {
            if let tabController = self.presentingViewController as? UITabBarController {
                if let navController = tabController.selectedViewController as? UINavigationController {
                    if let secondTab = navController.viewControllers.first as? HomeViewController {
                        secondTab.tfData = "YES"
                    }
                } else {
                    if let secondTab = tabController.selectedViewController as? HomeViewController {
                        secondTab.tfData = "YES"
                    }
                }
            }
        }
Nilesh R Patel
  • 697
  • 7
  • 17