Segue won't execute Swift - ios

I have a segue running form a Collection View (wrapped in a view controller) in to a another view controller, how ever the function never gets called:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
println(segue.identifier)
println(sender)
println("SEGUE SELECTED: \(segue.identifier)")
if(segue.identifier == "segueToDetailView") {
let cell = sender as CollectionViewCell;
}
}
Have placed a breakpoint at start of function but never reached.
Any input appreciated.

I will suggest not to create segue(s) from cell or any object(like button).
Create segue from one ViewController to OtherViewController with unique identifier.
And then call the performSegueWithIdentifier yourself using the identifier.

Related

performSegue creates two view controllers

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.

prepareForSegue and PerformSegueWithIdentifier sender

I am wondering about how the functions in the title work and also about the sender parameter.
Lets say a button click calls the performSegue method, does that also call the prepareSegue method as well? Is the prepareSegue method called before the performSegue method but after the button is pressed?
Also, is the "sender" parameter in both of the functions linked? If I pass in a string as the sender in the performSegue method, will that transfer over to the sender parameter in the prepareSegue method? In other words, if I set the sender parameter in the performSegue method as "Hi world", will the sender parameter in the prepareSegue method also be the same string?
Thanks
There are, effectively, two ways you can trigger a segue. The first is via an action on a UI element in Interface Builder, the second is using performSegueWithIdentifier:sender: in your code. I say 'effectively', because under the covers, when the scene is loaded from the storyboard, an action handler is configured that ultimately calls performSegueWithIdentifier:sender:
When performSegueWithIdentifier:sender: is called, the segue object is delivered to your view controller's prepareForSegue:sender: function.
In the case where the segue was initiated by an action on a UI element then the sender will be that UI element (i.e. if it is an action connection on a UIButton then the sender will be the UIButton instance).
If the segue is initiated by your code calling performSegueWithIdentifier:sender: then the sender will be whatever object you passed as the sender. This could be your view controller, a button, an array, anything. So yes, if you pass "Hello World" to performSegueWithIdentifier:sender: as the sender value then this will be the sender in prepareForSegue:sender:
In terms of the order of operations:
performSegueWithIdentifier:sender is called, either by your code or as a result of an action on a UI element
If your view controller implements shouldPerformSegueWithIdentifier:sender: then this function is called. If this function returns false then the segue is cancelled
The segue object and destination view controller object are created
If your view controller implements prepareForSegue:sender: then this function is called.
Once prepareForSegue:sender: returns, the segue completes.
The performSegue method calls a segue to be performed from one view to another. Before the segue actually takes place, the prepareForSegue method is called, and if you want to pass data between the views, you'd do it there.
The performSegue method doesn't take the parameter you want to send. It's only used to call the segue in the first place. Any data that you want to send will be done through prepareForSegue.
Here's an example.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
performSegueWithIdentifier("test", sender: self)
//You can set the identifier in the storyboard, by clicking on the segue
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "test"{
var vc = segue.destinationViewController as! RandomViewController
vc.data = "Data you want to pass"
//Data has to be a variable name in your RandomViewController
}
}
Let me know if this helps!
The_Curry_Man's answer worked for me. Here's an update of his code for Swift 3.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
performSegue(withIdentifier: "test", sender: self)
//You can set the identifier in the storyboard, by clicking on the segue
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "test"{
var vc = segue.destinationViewController as! RandomViewController
vc.data = "Data you want to pass"
//Data has to be a variable name in your RandomViewController
}
}
my two cents for beginners... In swift 3 is:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
}
So, if arriving controller (of class MyController) implements a "fillData" method:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destController = segue.destination as MyController{
destController.fillData(...)
}
}
Updated Method for Swift 5
performSegue(withIdentifier: "showNextViewController", sender: self)
Note : "showNextViewController" is identifier added for segue in storyboard
while sending any object to the particular object to another view controller by using perform segue with an identifier, Please follow the steps #Swift4
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Detailed_Live_poll"{
let destinationNavigationController = segue.destination as! UINavigationController
let targetController = destinationNavigationController.topViewController as! NewLivePollViewController
targetController.dictQuestInf = sender as! NSDictionary
}
}

How can i create a segue that pass data to another view controller only if certain criteria are met

I want to create a segue to pass data to another view controller but there are certain criteria that must happen for the segue to happen. If possible i would prefer to use the segue Id instead of the dragging method.
this is an example Im trying to accomplish
#IBAction func SubmitButtonPressed(sender: AnyObject) {
if 1<0 {
// dont perform segue
}else{
//Perform segue
// i want to pass this data in the next VC
var data = "foo"
//this is my segue id i want o use to go to the Second VC
var segueId = "segueForgotPasswordTwo"
// second VC
var secondVc = "viewController2"
// Iwant to to use prepare for segue but im getting errors in the parameters
prepareForSegue(UIStoryboardSegue, sender: AnyObject?){
}
}
}
Your question is a bit unclear but I believe this is what you are looking for...
func someFunction(){
if //some condition {
//code
}else if //some condition {
//code
} else {
//perform segue by using the folowing line. Assign the identifier to the segue in the storyboard.
//Do this by first creating a segue by dragging from a view controller to the destination view controller. Be sure to drag from the VIEWCONTROLLER, to the destination VIEWCONTROLLER. DO NOT just drag from the button. Next, choose the type of segue (eg. show or present modally), and then type in an indentifier for this segue.
performSegueWithIdentifier("SegueIdentifier", sender: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueIdentifier" {
//now find your view controller that you are seguing to.
let controller = segue.destinationViewController as! SomeViewController
//access the properties of your viewController and set them as desired. this is how you will pass data along
controller.property = someValue
}
}
Overview:
Hook the segue from the source view controller to the destination view controller (see left side red arrows)
Don’t hook it from the button to the destination view controller
Create an action for the button to do your custom condition check then perform segue
Screenshot:
Code:
var data = "foo"
#IBAction func buttonPressed(sender: UIButton) {
let someCondition = true
if someCondition {
performSegueWithIdentifier("showGreen", sender: self)
}
else {
performSegueWithIdentifier("showPink", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showGreen" {
let greenVC = segue.destinationViewController as! GreenViewController
// Make sure the data variable exists in GreenViewController
greenVC.data = data
}
}
You can implement the shouldPerformSegueWithIdentifier function in your ViewController. When the segue is triggered, this function can cancel the segue if it returns false, so you can simply include whatever logic is required in this function and return true/false as appropriate.

Swift - Unwind Segue triggering error

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
}
}

How to specify which view controller you are preparing for with Swift's prepareForSegue function?

So I have multiple buttons on one view segue'ing to other views. I have the function prepareForSegue() at the bottom of my code preparing one segue, however the app crashes when I use another segue on the view, even if it doesn't need any preparing.I think that the problem is that all of the segues use the prepareForSegue() function, however the storyboard ID is different than the view it is transitioning to.Is there any way to specify a prepareForSegue() function for each separate segue on the same view?Code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let theVC: ViewController = segue.destinationViewController as! ViewController
theVC.receivedString = "true"
}
Thanks
In your prepareForSegue you should use a condition to check segue identifier like:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "yourSegueToAnyController")
{
//do code for specific viewController
}
}

Resources