I have setting like this:
First controller reads data and sets in Second Controller.
Second Controller has a button that executes push segue to Third Controller with a countdown.
After countdown I want to go back from third controller to second that should still have data. Is there any way to achieve this?
Also I am using Storyboards.
I send data to Second Controller in prepare func. Second to Third controller change is connected directly to button in Storyboards.
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
let controller = segue.destination as! QuestionViewController
controller.questionIDs = sender as! [Int]
}
To come back from Third to Second controller I use this code from Third controller:
self.performSegue(withIdentifier: "nobodyAnsweredSegue", sender: self)
Change this:
self.performSegue(withIdentifier: "nobodyAnsweredSegue", sender: self)
To this:
self.navigationController?.popViewControllerAnimated(true)
Related
How do I replace a ViewController and also send some parameters?
With the code below, I can only push another ViewController into my current Navigation Stack.
Can we just pop and push another one immediately? Or is there an official to replace for good? Please kindly show me. Thank you.
Perform Segue
performSegue(withIdentifier: "ToNewViewController", sender: self)
Prepare Segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! NewViewController
destinationVC.params = params
}
If you have a navigation controller as your app window root , then you can manage all viewControllers
var vcs = self.navigationController!.viewControllers // get all vcs
vcs = vcs.dropLast() // remove last vc
let vc = // create new VC
vcs.append(vc) // append it
Then alter that array and set it back like this
self.navigationController!.setViewControllers(vcs,animated:true)
OR
You can get the top presented vc with this , then add a method to that vc to do the data replacement and refresh of your UI
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
self.delegate = segue.destination as? MenuViewController
print("check_1", self.delegate)
}
#IBAction func openMenu(_ sender: Any) {
performSegue(withIdentifier: "openMenu", sender: sender)
print("check_2", self.delegate)
}
My main ViewController updates values while MenuViewController displays these values. Each time ViewController values are updated, it calls self.delegate.updateValues in MenuViewController. I transition between the two ViewControllers through buttons.
My problem is that it seems like the MenuViewController displayed is a different object than the one stored in self.delegate inside ViewController. Printing the check statements:
check_1 Optional(<Menu.MenuViewController: 0x10161ca10>)
check_2 Optional(<Menu.MenuViewController: 0x10161ca10>)
check_1 Optional(<Menu.MenuViewController: 0x10161dd10>)
May I ask how do I make sure only one instance of MenuViewController is created and stored in self.delegate?
When you add a segue to a storyboard, if you hook up the segue to a specific button/IBAction, you don't need to call performSegue manually, it will be automatically called for you.
You have 2 segues executed, since both the storyboard executes the segue and then you also do it from code by calling performSegue.
performSegue should only be used when your segue isn't directly hooked up to a UI event or if you need to conditionally perform a segue - such as when you have a login button, where depending on the network response, you might execute an error or a login segue.
I am woking on an recording APP.
I tried to add navigation controller in my first recording viewcontroller which then could pass filename array to the second viewcontroller using the following function prepare:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let controller = segue.destination as? MainViewController
controller?.recordArray = recordingArray
self.present(controller!, animated: true, completion: nil)
}
However, when ran in the simulator the navigation bar disappeared in the second controller and Xcode pops out the warning
Thread1: EXC_BAD_ACCESS(code=2,address=0x7fff51edfff8)
Has anyone got any advice?
Thanks!
Don't ever call present(_:animated:completion:) inside prepare(for segue:).
prepare(for segue) is called automatically by the system just before a segue is about to happen to let you prepare the data for sending to the destination viewcontroller or do any other calculations you need to before performing the segue. A segue needs to be set up in Storyboard and it will either be called automatically or if it is a manual segue, you need to call it using perform(segue) and once you do that, the system will call prepare(for segue) for you. You can see why calling another navigation function proves to be problematic, since you are trying to navigate to another viewcontroller using two different methods (segue and present).
If you haven't set up the segue in Storyboard, then you also need to do that, since if it is not set up, let controller = segue.destination as? MainViewController will be nil.
Once you set up the segue in Storyboard, this is how your function should look like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller = segue.destination as? MainViewController {
controller.recordArray = recordingArray
self.present(controller, animated: true, completion: nil)
}
}
You shouldn’t be trying to present a VC in this method, it’s just a place for you to configure the destination VC before the segue presents it
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard let controller = segue.destination as? MainViewController else { return }
controller.recordArray = recordingArray
}
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 am using for the first time the Unwind Segue approach. I have multiple view controllers as can be seen in the picture below (a few of them shown of course). In the Edit Profile I have a Done button. Once clicked I trigger an IBAction that triggers an unwind segue.
Here is the code for the Done button in the nav bar:
#IBAction func unwindToMainViews(sender: UIStoryboardSegue) {
//let sourceViewController = sender.sourceViewController
self.performSegueWithIdentifier("unwindToMainSegue", sender: self)
}
and in the
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
I am doing the following to pass data from Edit Profile back to Home View
if (segue.identifier == "unwindToMainSegue") {
// pass data to next view
let tabCtrl = segue.destinationViewController as! UITabBarController
let destinationVC = tabCtrl.viewControllers![0] as! HomeViewController
destinationVC.userObject = self.userObject;
}
When segue identifier is matched and code is executed (to transfer userObject from this controller to another), it triggers the error:
Could not cast value of type 'app.EditProfileViewController' (0x100b99d80) to 'UITabBarController' (0x104a1d030).
How can this error be fixed? I am surprised since i am casting to UITabBarController so thought it should work.
You don't return to the UITabBarController in an unwind segue. You return to the ViewController that triggered the original segue, or one if its ancestors.
As #jlehr stated in the comments:
Unwind segues don't return to anything; they dismiss any pushed and
presented view controllers between the source and destination view
controller. The destination is wherever the implementation of the
unwind method is found, regardless of how the source view controller
was presented.
To unwind to the viewController that triggered the original segue, you need to implement the #IBAction func returnToHere(segue: UIStoryboardSegue) function in the viewController you want to return to.
Then when you set up your Done button by dragging to the Exit icon, you select returnToHere from the pop-up.
To pass data back to the sourceViewController, give your unwind segue an identifier such as "unwindToSource", then override prepareForSegue in the viewController you are returning from:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "unwindToSource" {
let dvc = segue.destinationViewController as! SourceViewController
dvc.userObject = self.userObject
}
}