performSegue creates two view controllers - ios

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.

Related

check the segue used to open viewController in the viewController itself

Having this methods:
//Metodo che verifica se proveniamo dal Profile controller o da un altro controller
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "accountSegue" {
self.DisattivaTutorialBtn.isHidden=true
IndietroBtn.isHidden=false
}else{
self.IndietroBtn.isHidden=true
self.DisattivaTutorialBtn.isHidden=false
}
}
I perform different actions basing on the segue's identifier.
Of course, this method isn't called anywhere (I understood that it is): how can I call it? It seems stupid but calling it as "self" method in "viewDidLoad" doesn't work.
To do that instead of performing your Segue on a button click in storyboard, create a segue from your viewcontroller to your other view controller. then when you want to go to the next view controller call below from your button click or any other action event.
self.performSegue(withIdentifier: "accountSegue", sender: self)
This will automatically call your prepareForSegue method and your if statement will execute.
If you are using manual segues in your Storyboard, you can perform the segue by calling self.performSegue(withIdentifier:sender:). See performSegue documentation.
If you are using segues whose type is not set to manual, when you click on the UI element to which the segue is linked in your Storyboard, prepare(for segue) will be called automatically by the system.
To perform Segue manually you need to attach the action
Following will help you go get the required thing done
performSegue(withIdentifier: "accountSegue", sender: nil)

prepare(for segue: UIStoryboardSegue, sender: Any?) Not firing in Xcode 8.1 swift 3 ios 10

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.

Swift 3: PerformSegue WithIdentifier Not Displaying View Controller, No Errors

When I execute the line below, my destination view controller is not visually presented but there are no errors in the log:
performSegue (withIdentifier: "DetailsViewController", sender: self)
Let's step back from a problem. Imagine my successful setup: ViewController is loaded and upon some user action the above line would actually open a new DetailsViewController. I tested - everything works as expected - so I know it works.
But the problem presenting DetailsViewController begins when I decide to implement some third party framework by adding a CamViewController to my ViewController and perform segue upon element tap inside CamViewController, then delegate method passing this action back to ViewController from which I would open DetailsViewController. With this architecture setup I get no errors in a log but visually nothing is opening. No DetailsViewController ever presented.
A bit more details of architecture:
ViewController presents CamViewController with line self.present(camViewController, animated: true, completion: nil)
CamViewController implements a protocol to call some method on user action
ViewController conforms to CamViewController protocol and delegate method successfully runs on user action (log shows it is working)
Calling DetailsViewController with segue identifier is executed successfully performSegue (withIdentifier: "DetailsViewController", sender: self) but DetailsViewController is never displayed on screen.
This method below prints prepare for segue Optional("DetailsViewController") which sounds correct.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("prepare for segue \(segue.identifier)")
}
I also tried adding super.performSegue - no luck
First I would change your segue code to something more like this.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "DetailsViewController"){
print("prepare for segue DetailsViewController")
} else {
print("prepare for segue other")
}
}

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

Segue won't execute Swift

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.

Resources