问题
I have a parent UIViewController
and it has two different view containers - each of them has embedded UIViewController
inside. It looks somehow like this:
I want to change the label on the right container when user presses the button stored on the left one.
So far I was able to do it while having a button placed in a parent view controller, then I was just using a protocol:
in my parent component I had:
class ParentController: UIViewController { var delegateEmbedded:HandleEmbedded? override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if (segue.identifier == "segueToFirstEmbeddedController"){ if let embeddedView = segue.destinationViewController as? EmbeddedContainer { self.delegateEmbedded = embeddedView } }
in my container-embedded UIViewController I had:
protocol HandleEmbedded: class { func setName(label: String) } class EmbeddedContainer: UITableViewController, HandleYourChat{ func setName(label: String){ print("setting label to \(label)") } }
Situation above works when I have the button placed in a parent controller and want to change the label inside a container. But what happens and how should I pass the data when the button is also embedded, but in a different container than the label? Do I have to pass the data through the parent controller? What's the best way for doing so?
回答1:
To pass data from one embedded ViewController to another embedded ViewController, have the parent handle the transfer. Here I have provided a complete example with three ViewControllers and a single StringTaker
protocol. Both the main ViewController
and the LabelViewController
implement this protocol. The main ViewController
takes a string from the ButtonViewController
and passes it on to the embedded LabelViewController
.
ViewController.swift
import UIKit
protocol StringTaker: class {
func takeString(string: String)
}
class ViewController: UIViewController, StringTaker {
weak var stringTaker: StringTaker?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedButtonViewController" {
let dvc = segue.destinationViewController as! ButtonViewController
dvc.delegate = self
} else if segue.identifier == "EmbedLabelViewController" {
let dvc = segue.destinationViewController as! LabelViewController
stringTaker = dvc
}
}
// Receive the string from the ButtonViewController
func takeString(string: String) {
// Pass it to the LabelViewController
stringTaker?.takeString(string)
}
}
ButtonViewController.swift
import UIKit
class ButtonViewController: UIViewController {
weak var delegate: StringTaker?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func generateString(sender: UIButton) {
let cities = ["Boston", "Paris", "Sydney", "Mumbai", "Lima"]
// Pick a random city
let city = cities[Int(arc4random_uniform(UInt32(cities.count)))]
// Pass the string to the delegate
delegate?.takeString(city)
}
}
LabelViewController.swift
import UIKit
class LabelViewController: UIViewController, StringTaker {
@IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func takeString(string: String) {
myLabel.text = string
}
}
Things to note:
- The
LabelViewController
and theButtonViewController
know nothing about theViewController
that uses them. This makes it easier to reuse them. You could embed them in another viewController and as long as you properly implement theStringTaker
protocol and set up thedelegate
, everything works. - The key to hooking this up in in naming the embed segues and then properly setting up the delegates in
prepareForSegue
. The segues can be found in the Document Outline view once the Container is added to theViewController
.
来源:https://stackoverflow.com/questions/36530453/how-can-i-pass-data-from-one-container-to-another-both-embedded-in-the-same-uiv