Passing Data to view controllers that are embedded in container views
In your Storyboard, when you embed a VC in a ContainerView, you also see a "segue" connecter. When the root VC loads, you will get a call to prepare for segue for that.
Give each storyboard-created segue an Identifier - such as "infoViewEmbedSegue", "feedViewEmbedSegue", etc.
In your root VC, I'm guessing that
var infos: BusinessProfilesDetails!
var feeds: BusinessProfilePostsFeed!
are variables to reference the content of infoView
? If so, in prepare() you want to:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// get a reference to the embedded PageViewController on load
if let vc = segue.destination as? BusinessProfilesDetails,
segue.identifier == "infoViewEmbedSegue" {
self.infos = vc
// if you already have your data object
self.infos.otherUser = theDataDict
}
if let vc = segue.destination as? BusinessProfilePostsFeed,
segue.identifier == "feedViewEmbedSegue" {
self.feeds = vc
// if you already have your data object
self.feeds.otherUser = theDataDict
}
// etc
}
Now you'll have persistent references to the actual View Controllers embedded in your Container Views, in case you want access to them in other parts of your root VC, e.g.:
@IBAction func btnTapped(_ sender: Any) {
self.feeds.otherUser = theDataDict
}
Pass data between ViewController and ContainerViewController
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
}
}
How to pass data from View controller to Container?
Set segue identifier in storyboard, first of all. You could find the field where can set identifier after click segue link.
View Controller which will call next ViewController
func showSomeViewController() {
self.performSegueWithIdentifier("TestContainer", sender: self);
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "TestContainer")
{
let vc: TestViewController = segue.destinationViewController as! TestViewController
vc.tmpString = "say ho"
}
}
and TestViewController
class TestViewController: UIViewController {
var tmpString: String!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
Share Data Between View Controller and Container View
You are on the right track to setup the delegate.
In Storyboard:
- create a Segue of type
Embed Segue
from theContainerView
to the ViewController to embed. - Select the segue and set a
Identifier
.
In Code, in prepareForSegue()
:
- Set the
myContainerView
propert Set the delegate
class ViewController: UITableViewController, ContainerViewDelegate {
var myContainerView:ContainerView? // we do initialize it in prepareForSegue()
var id: String!
override func viewDidLoad() {
super.viewDidLoad()
id = "123"
// myContainerView.delegate = self //myContainerView is nil here. We set it in prepareForSegue
}
func initialize() -> String {
return id
}
let embedSegueID = "the identifier you set to your embed segue in Storyboard"
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == embedSegueID) {
let dvc = segue.destination as! ContainerView
// Now you have a pointer to EmbeddedViewController.
// You can save the reference to it, or pass data to it.
myContainerView = dvc
myContainerView.delegate = self
}
print(segue.identifier)
}
}
If you want to pass data from your ViewController to AnotherViewController which is embedded in your destinationViewController (how I understand your question), I would:
- pass it to destinationViewController as in the example above (prepareForSegue)
- than pass it to AnotherViewController in
viewWillAppear()
from within destinationViewController.
In this case, how I understand your usecase, you do not need the delegate and can remove all delegate related code (initialize
, the ContainerViewDelegate
protocol, the property var delegate: ContainerViewDelegate!
and all calls to it.
What's the easiest way to pass data between two simultaneously displayed view controllers?
Creating Delegates
Start with creating delegates for both of your container ViewControllers. Don't forget to add : class
. If you didn't do it, you wouldn't be able to create weak delegate variable:
protocol TopViewControllerDelegate: class {
func sendMessage(_ string: String)
}
protocol BottomViewControllerDelegate: class {
func sendMessage(_ string: String)
}
Now for every container ViewController create weak delegate variable
class TopViewController: UIViewController {
weak var delegate: TopViewControllerDelegate?
...
}
class BottomViewController: UIViewController {
weak var delegate: BottomViewControllerDelegate?
...
}
then for TopVC implement Bottom's delegate and for BottomVC Top's.
extension TopViewController: BottomViewControllerDelegate {
func sendMessage(_ string: String) {
// do something
}
}
extension BottomViewController: TopViewControllerDelegate {
func sendMessage(_ string: String) {
// do something
}
}
Assigning Delegates
Your segues between main ViewController and containers should have their own identifiers: EmbedTop
, EmbedBottom
.
So in your WrapperViewController
create variable for your Top and Bottom ViewController and override method prepare(for:sender:)
and inside assign these variables
class WrapperViewController: UIViewController {
var topVC: TopViewController?
var bottomVC: BottomViewController?
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EmbedTop" {
topVC = segue.destination as! TopViewController
} else if segue.identifier == "EmbedBottom" {
bottomVC = segue.destination as! BottomViewController
}
}
}
finally in viewDidAppear
set delegate of TopVC's as BottomVC and of BottomVC's as TopVC
override func viewDidAppear(_ animated: Bool) {
topVC.delegate = bottomVC
bottomVC.delegate = topVC
}
Now your two ViewControllers can speak with each other! :-)
Example:
class BottomViewController: UIViewController {
...
func speakToTop() {
delegate?.sendMessage("Hi Top!")
}
}
Swift: How to pass data to PageViewController which is embedded in ContainerView?
Somehow during my own brainstorm on this problem, I found out that I ommited the most straightforward solution:
1) Create C and D instances inside A
2) Pass them to B using prepareForSegue
method
3) In B assign them to according VC's
4) Voila, I can access their variables and functions right from A
how to load child view controllers or container views - Swift
As i understand there are 2 container views and you want to see the blue view when the segmented is first and you want to see the green view when the segmented is second if it is true the solution is like this;
You should init the uivew(hold on the ctrl and drag it to viewcontroller for both blue and green container view)(you need to add 2 different container view) and write
if segmented.selectedIndex == 0 {
greenView.isHidden = true
blueView.isHidden = false
} else if segmented.selectedIndex == 1 {
greenView.isHidden = false
blueView.isHidden = true
}
Related Topics
Xcode 6 - Launch Simulator from Command Line
Iphone: Where the .Dsym File Is Located in Crash Report
Uicollectionview's Cell Disappearing
Using Audiobufferlist with Swift
Remove Grey Background on Link Clicked in iOS Safari/Chrome/Firefox
Uiscreen Mainscreen Bounds Returning Wrong Size
Creating Delegates on the Spot with Blocks
Posting Video on Instagram Using Hooks
How to Get Rgb Values from Uicolor
Difference Between Dispatchqueue.Main.Async and Dispatchqueue.Main.Sync
How to Throttle Search (Based on Typing Speed) in iOS Uisearchbar
Set Dimensions for Uiimagepickercontroller "Move and Scale" Cropbox
Swift Doesn't Convert Objective-C Nserror** to Throws
iOS 9 Safari: Changing an Element to Fixed Position While Scrolling Won't Paint Until Scroll Stops
Set Default iOS Local Notification Style for Application