James
James

Reputation: 1177

Pass data between ViewController and ContainerViewController

I'm working on an app, and need to pass data between view and containerView. I need to send data and receive data from both Views.

Let me explain better:

I can change the Label Master (Touch the Container Button) by protocol, but I can not change the Label Container (Touch the Master button). What happens is the Master connects with the container by a following. But do not have a follow Container linking to the Master.

I tried to add but segue to, but it worked.

enter image description here

The Master View Controller:

import UIKit

protocol MasterToContainer {
    func changeLabel(text:String)
}

class Master: UIViewController, ContainerToMaster {

    @IBOutlet var containerView: UIView!

    var masterToContainer:MasterToContainer?

    @IBOutlet var labelMaster: UILabel!


    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "containerViewSegue" {
            let view = segue.destinationViewController as? Container
            view!.containerToMaster = self
        }
    }

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

    @IBAction func button_Container(sender: AnyObject) {
        masterToContainer?.changeLabel("Nice! It's work!")
    }


    func changeLabel(text: String) {
        labelMaster.text = text
    }
}

The Container View Controller:

import UIKit

protocol ContainerToMaster {
    func changeLabel(text:String)
}

class Container: UIViewController, MasterToContainer {

    var containerToMaster:ContainerToMaster?

    @IBOutlet var labelContainer: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func button_Master(sender: AnyObject) {
        containerToMaster?.changeLabel("Amazing! It's work!")
    }


    func changeLabel(text: String) {
        labelContainer.text = text
    }
}

Can someone help me?

Upvotes: 18

Views: 23119

Answers (3)

Saeed Rahmatolahi
Saeed Rahmatolahi

Reputation: 1338

you can use this extension to access the container child

extension UIViewController {
  func getContainerChild<vc:UIViewController>(_ viewController : vc,_ hasNavigation : Bool = true) -> (vc) {
    guard let vc = self.children[0] as? UINavigationController else {return viewController}
    if hasNavigation {
        guard let childVC = vc.children[0] as? PurchasedHistoryListVC else {
            return viewController}
        return childVC as! vc
    } else {
        return vc as! vc
    }
   }
}

so you can do some thing like this in your view Controller

let vc = self.getContainerChild(yourChildViewControllerClass())
vc.functionName()

Upvotes: 0

Rob
Rob

Reputation: 2660

I solved it with this code

To send data from ViewController -> ContainerViewController

Class ViewController : UIViewController {

func sendData(MyStringToSend : String) {

let CVC = childViewControllers.last as! ContainerViewController
CVC.ChangeLabel( MyStringToSend)
}

}

in your ContainerViewController

Class ContainerViewController : UIViewController {

@IBOutlet weak var myLabel: UILabel!

func ChangeLabel(labelToChange : String){

myLabel.text = labelToChange

 }
}

To send data from ContainerViewController -> ViewController

Class ContainerViewController : UIViewController {

func sendDataToVc(myString : String) {

   let Vc = parentViewController as! ViewController
   Vc.dataFromContainer(myString)
 }

}

and in ViewController

  Class ViewController : UIViewController {

  func dataFromContainer(containerData : String){

   print(containerData)
  }

  }

I hope this will help someone.

Upvotes: 29

T Blank
T Blank

Reputation: 1418

All you need to do is keep a reference to Container in your master view controller.

That is, you should add an instance variable to Master that will hold a reference to the view controller, not just the view. You'll need to set it in prepareForSegue.

So the beginning of Master View Controller would look something like this:

class Master: UIViewController, ContainerToMaster {

@IBOutlet var containerView: UIView!

var containerViewController: Container?

@IBOutlet var labelMaster: UILabel!

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "containerViewSegue" {
        containerViewController = segue.destinationViewController as? Container
        containerViewController!.containerToMaster = self
    }
}

And then in your button function, simply change the label using the variable you just added.

Example:

@IBAction func button_Container(sender: AnyObject) {
    containerViewController?.changeLabel("Nice! It's work!")
}

This means you can get rid of your MasterToContainer protocol too.

I tested this code, so I know it works, but unfortunately I am an Objective-C dev, and know nothing about best practices in Swift. So I don't know if this is the best way to go about it, but it certainly works.

Edit:

Here's the exact code I've tested:

Master.swift:

import UIKit

class Master: UIViewController, ContainerToMaster {

    @IBOutlet var containerView: UIView!
    @IBOutlet var labelMaster: UILabel!
    var containerViewController: Container?

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "containerViewSegue" {
            containerViewController = segue.destinationViewController as? Container
            containerViewController!.containerToMaster = self
        }
    }

    @IBAction func button_Container(sender: AnyObject) {
        containerViewController?.changeLabel("Nice! It's work!")
    }

    func changeLabel(text: String) {
        labelMaster.text = text
    }
}

Container.swift:

import UIKit

protocol ContainerToMaster {
    func changeLabel(text:String)
}

class Container: UIViewController {

    @IBOutlet var labelContainer: UILabel!
    var containerToMaster:ContainerToMaster?

    @IBAction func button_Master(sender: AnyObject) {
        containerToMaster?.changeLabel("Amazing! It's work!")
    }

    func changeLabel(text: String) {
        labelContainer.text = text
    }
}

Upvotes: 33

Related Questions