I have a container view in my Storyboard that displays another view controller that I already programmed and stuff. I want to communicate between the main View Controller and the contained-view controller. I know how to use delegates and I am comfortable with using them, however I normally set up delegates when I initialize a ViewController, however in this case I don't know where to apply this, since the view controller is already there per the storyboard. Normally I would do something like this:
class HomeVC: UIViewController {
func initializeVC() {
resultsVC = self.storyboard?.instantiateViewController(withIdentifier: "resultsView") as! GoalsVC
resultsVC.calcDelegate = self //I set the "HomeVC" as the Delegate since it has all the functions I need
}
}
As mentioned above, since I never really created this view controller via code, I don't know how to assign a delegate (specially setting the delegate to "self" (where Self is the main View Controller)
You can assign delegate in prepareforsegue. Like below code
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "container_segue") {
let controller = segue.destination as! containerController
controller.delegate = self
}
}
When project runs, this method called automatically because we had created segue in the storyboard.
By using segue.identifier you can check for which controller segue is going to happen and accordingly you can achieve your requirement.
As you are using storyboard for container view. There is a segue with embed type. Give this segue a identifier, say MyContainedViewControllerSegueId
Then in prepare(for segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MyContainedViewControllerSegueId" {
// here you get your contained view controller as `segue.destination`
// cast it your subclassed view controller
// use delegate on that subclassed view controller for communication purpose.
}
}
Related
I have a masterViewcontroller with the container on it and a 2ndViewController embeded via storyboard in that. I am wondering how to access the 2ndViewController from the masterViewController.
I have seen about using prepare for segue but this doesn't seem to get called for when my viewController in the container is shown. Is there something I need to hook up for it to appear in the prepare for segue function?
Or is there another way to achieve this?
You need to override prepare(for segue: sender:) in the masterViewController class.
The segue needs an identifier in the storyboard. In prepare, you then check if the segue to be prepared for is the one you gave the identifier to via segue.identifier == "yourIdentifier".
Then you can resolve the embedded ViewController as your 2ndViewController like so:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "yourIdentifier" {
let child = segue.destination as! 2ndViewController
}
}
By the way, if you use as!, you're force-unwrapping segue.destination as your 2ndViewController class. If you're not 100% certain this segue will always have that class as it's destination, consider instead using as? to treat child as optional and then doing additional checks for it's existence before attempting to use it.
I have a view controller and a UISearchBar in the Navigation controller of it. I have added a Container View which then contains 2 ViewControllers.
I need to pass a variable to my Container View and the View Controllers of the Container View. However I can't do that because prepareForSegue happens Earlier than viewDidLoad() of my main VC.
I need to pass these variables to my Container View but prepareForSegue gets called before these variables are initialised
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("prepare for segue FirstViewController")
if segue.identifier == "mapViewContainer" {
let vc = segue.destination as! MasterMapViewController
vc.segmentControl = self.container
vc.resultsViewController = self.resultsViewController
vc.searchController = self.searchController
}
}
Picture
Try to initialize these variables not in the viewDidLoad, but in the prepareForSegue method.
I have my UIViewController, which is a person's profile page, it displays their name and picture. Within that UIViewController I have a UIContainerView that displays a static UITableView. I'm having a little trouble updating the cells of the table when the profile page loads. Here's my storyboard:
I have tried the following, within my UIViewController.
I created an outlet to my UIView and passed the person object to it.
In my UIView I called the segue to pass the object to the UITableViewController and from there I was going to update some labels.
func prepareForSegue(segue: UIStoryboardSegue!, sender: Any?){
if segue.identifier == "containerSegue"{
let statsTable = segue.destination as! CollectionTableViewController
statsTable.currentPerson = currentPerson
}
}
My Segue is never called though. I have moved it to the main UIViewController in case it should be called from there, but again not called. What am I doing wrong with this approach?
Assuming you have set the Segue Identifier to "containerSegue" you should get it in your "Stats" view controller.
Are you using Swift 3? It's possible you just have the func definition wrong:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "containerSegue" {
let statsTable = segue.destination as! CollectionTableViewController
statsTable.currentPerson = currentPerson
}
}
That should work.
I have a tabbed view controller that is associated with two view controllers.
I need to pass an array from the first View Controller to the Second View controller.
In Order to do this I have the following code in my first VC:
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "AddItem"
{
if let destinationVC = segue.destination as? SecondViewController
{
destinationVC.toDoList = toDoList
}
}
}
However this is not getting fired when I switch two the second VC using the tab button.
Any ideas as to why this is not getting fired?
This is how my main storyboard looks like:
Main Storyboard
You cannot transfer objects between tab views through segue because the VC is not actually making a direct segue connection rather you can do it with a delegate or a notificationCenter post and observe to transfer
You have to put that segue code in Tabbar controller class. You shouldn't put that thing in firstVC. Because there is no segue is going on from first VC to Second VC.
I want to segue from a view container within "H" that is presented using the navigation controller connected to the Split View Controller. How can I accomplish this? I have tried regular performSegueWithIdentifier using locally linked storyboard ID's but that removes the top navigation bar. I want to retain the top navigation bar and execute the segue as if it was done using the master navigation controller (rows that select which view controller is being presented in the detail view).
Any help is greatly appreciated!
Here is an example of how to perform a segue from an embedded ViewController.
ViewController.swift
import UIKit
protocol SegueHandler: class {
func segueToNext(identifier: String)
}
class ViewController: UIViewController, SegueHandler {
func segueToNext(identifier: String) {
self.performSegueWithIdentifier(identifier, sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destinationViewController as! HViewController
dvc.delegate = self
}
}
}
HViewController.swift
import UIKit
class HViewController: UIViewController {
weak var delegate: SegueHandler?
#IBAction func pressH(sender: UIButton) {
delegate?.segueToNext("GoToGreen")
}
}
Setup:
Use delegation to have the HViewController tell its embedding viewController to perform the segue.
Create a protocol called SegueHandler which just describes a class that implements the method segueToNext(identifier: String).
protocol SegueHandler: class {
func segueToNext(identifier: String)
}
Make your viewController implement this protocol by adding it to the class declaration line:
class ViewController: UIViewController, SegueHandler {
and by implementing the required function.
Add a delegate property to HViewController:
weak var delegate: SegueHandler?
Click on the embed segue arrow between ViewController and HViewController. Give it the identifier "EmbedH" in the Attributes Inspector.
Create a show segue between ViewController and the GreenViewController by Control dragging from the viewController icon at the top of ViewController to the GreenViewController. Name this segue "GoToGreen" in the Attributes Inspector.
In prepareForSegue for ViewController, when the "EmbedH" segue happens, set the delegate property of HViewController to self (ViewController).
When the user clicks the H button in the HViewController, call delegate?.segueToNext("GoToGreen") to trigger the segue in ViewController.
Here it is running in the simulator:
I was needing exactly what #vacawama proposed here, though I couldn't reproduce that, I tried exactly your steps but self.delegate?.segueToNext("GoToGreen") got called but neither the protocol itself nor the container view controller. After an entire day searching about this approach I realized the problem was with the swift version. Just replace this:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destination as! HViewController
dvc.delegate = self
}
}
for this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destination as! HViewController
dvc.delegate = self
}
}
Other detail I was missing was about the embedded segue. Be sure to connect the container View to the HViewController, not the View Controller itself, otherwise the Embed option for segue won't appear.