Reputation: 1177
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.
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
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
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
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