I have looked for this problem everywhere.
I know how the unwind scene works. I have implemented the following code in the A VC
-(IBAction)returned:(UIStoryboardSegue *)segue {
try.text = #"Returned from Scene 1";
}
But when I go to my B VC(Which is the VC I want to go back to A VC from) and ctrl drag a button onto the exit at the bottom it will not allow me to. And no function pops up in the exits option. Anyone else had this issue or can help?
To set up an unwind segue, you should
Set up your two scenes with the standard modal or push segue between them:
Define the custom classes for those two scenes to be your respective view controllers.
Implement the action in the .m for view controller A:
- (IBAction)unwindToA:(UIStoryboardSegue *)segue
{
//returning to A
}
Then you can create a segue in B by control-dragging (or right-click-dragging) from some control down to the exit outlet in the bar below scene B:
And if everything above is configured correctly, you will now see your unwind segue listed in a popover:
To make Exit outlet active, add this code to viewController. Now you should be able to ctrl-drag to exit outlet.
It is actually quite odd, that there should be empty method to make it work.
swift
#IBAction func unwindSegue(unwindSegue:UIStoryboardSegue)
objC
- (IBAction)unwindSegue:(UIStoryboardSegue *)sender;
I also had a problem with this even though everything was set up correctly. Eventually I tried closing the project and reopening it and that did the trick. Must have been some bug in Xcode.
This doesn't seem to have been the cause of your problem but I thought I'd add the answer in case someone else has the same problem.
#LoPoBo, #hozefam, & #Van Du Tran
If closing down isn't working, perhaps you were dragging in the wrong manner. Instead of clicking on the Bar Button Item and dragging from Action Segue to the exit try just right click -> hold & drag to exit segue. This was messing with me for a good 20min before I figured it out. Hope this helps someone else too. Using xcode 6.1
Related
Trying to perform a segue "toLogin" when the login button is pressed. Segue is named and I control-dragged the button to the block of code to make sure they are associated. Very new to coding and not sure where I went wrong.
Currently, when button is pressed it changes color but does nothing. I also previously set it to print something when pressed but that never occurs either.
Screenshot of code, storyboard
For you to connect a button to a function, the function needs to look like below
#IBAction func login(_sender: Any) {
}
You will then need to connect to the blank circle next to the function on the left.
Regarding your screenshot, each segue linked to the whole main storyboard as highlighted showing. Not linked to button. Remove those two segues from storyboard first, and linked each segue to storyboard reference or next View Controller as attached image.
Make sure you have connected your button to the #IBAction in your UIViewControllerConnect IBAction to UIButton
Looks like you are triggering segue through UIBarButtonItem,
Swift 4.2,
loginButton.action = #selector(login(sender:))
#objc func login(sender: UIBarButtonItem) {
//Perform segue
}
Thanks for answering everybody. I'm still not sure what exactly my issue was but I decided to re-create the storyboard page without using UIBarItems and it worked. I'm guessing that something about the UIBar was preventing interaction.
My app's navigation flow looks a bit like this:
UINavigationController - MasterViewController > DetailViewController > InfoViewController
MasterViewController contains the following method:
#IBAction func unwindToMaster(with segue: UIStoryboardSegue) {}
In DetailViewController, there is a similar method:
#IBAction func unwindToDetail(with segue: UIStoryboardSegue) {}
I use these methods, along with UIButtons, to allow the user to advance forward and back through the navigation hierarchy. In interface builder, I see the method under DetailViewController when I right click on "Exit" in InfoViewController, but when I right click on "Exit" in DetailViewController, no other unwind segues are listed.
I have consulted multiple online sources (Ray Wenderlich, relevant StackOverflow questions) instructing the correct way to produce unwind segues in interface builder, but none of these have helped solve the issue. Right now, I need help figuring out what the problem is in the first place. As development usually goes, it's probably something staring me square in the face.
I am running Xcode 8.1 using Swift 3. Thank you.
To re-iterate: not only an Action for a Storyboard Unwind Segue has to be placed in the same source file as class definition for an unwind-to (destination) View Controller (e.g., #IBAction func prepareForUnwind(segue: UIStoryboardSegue), detected as prepareForUnwind[With]Segue in a "Presenting Segues" list), but also that View Controller cannot have ANY extensions in ANY secondary source files. You have to merge class definition and all extensions into a single source file.
(As of Xcode 8.2.1.)
In my case, I had a complicated inheritance in my view controller and it was a reason why Interface Builder did not see my unwind. So this workaround works for me well:
Go to YouCollViewController.swift file and delete all classes, protocols, generics, etc. your view controller implements in view controller's declaration
Inherit your view controller from UIViewController
Go to the storyboard and connect your action with the unwind, it should appear in unwinds list
Go back to YouCollViewController.swift file and discard all the changes
I consulted Apple's Developer Library (specifically the page "Using Unwind Segues"). There, the example definition of an unwind action is:
#IBAction func unwindToMainMenu(sender: UIStoryboardSegue) {
let sourceViewController = sender.sourceViewController
// Pull any data from the view controller which initiated the unwind segue.
}
Applying this example in my code, I changed my unwind action declarations to:
#IBAction func unwindToMaster(sender: UIStoryboardSegue) {
print("Unwinded to master.")
}
and
#IBAction func unwindToDetail(sender: UIStoryboardSegue) {
print("Unwinded to detail.")
}
I also made sure that each method was contained within the same file as MasterViewController's class declaration. After further testing, I found that all extensions of MasterViewController had to exist in the same file for interface builder to find and recognize the unwind segue.
Now, in storyboard, the exit menu shows both unwind segues. My conclusion is that by fiddling around with where the methods are placed and how they are declared, a configuration that interface builder can recognize will be found. I hope it will be less touchy in the future, as my current method organization is very long and difficult to navigate.
Because none of these answers helped me and I didn't want to mess around with my code that much. Here another solution you can give a try.
Starting from the point where you have already added the unwind function to your MasterViewController.
First I have gone ahead and added a new ViewController to my storyboard as well as a new Cocoa Touch Class File of type UIViewController and connected it with my Storyboard one (I called it the HelperViewController).
Then you can add the same unwind function, you already have inside your MasterVC to your newly created HelperVC.
#IBAction func unwindToMaster(with segue: UIStoryboardSegue) {}
Now connect the Helper to your DetailVC. Your Storyboard should look somewhat like mine. You should get the same option as me if you ctrl + drag and drop to the exit of your DetailVC. When the connection has been established and you hover over the newly created segue both the Master and the HelperVC should be highlighted. Now you can delete the HelperVC again and everything should work as expected.
I hope that helped!
With swift 4 XCode 9.2 I found that you need to drag the reference from the yellow icon at the top of the viewController to the "Exit" reference of the target viewController in the left details panel. Hope this helps!
Sometimes XCode restart makes the actions appear.
This might be more of an xcode problem though I'm hoping someone might know someway to help.
I have a VC A that push's to VC B.
In VC A I have defined - (IBAction)doneUnWindingFromBToA :(UIStoryboardSegue *)segue {}
In VC C I defined - (IBAction)doneUnWindingFromBToC :(UIStoryboardSegue *)segue {}
When I drag a UIButton to the Exit button I only see doneUnWindingFromBToC - even though, that push segue has been deleted in the storyboard.
Currently, there is only one segue (push, from A to B) leading into B.
I have also tried to manually create a segue - dragging the scene's view controller icon to its exit icon.
How do I reset the dropdown?
UPDATE:
I commented out the code in VC C and now VC B doesnt let me ctrl drag into the Exit icon.
Its a bug. I'll file a report soon.
I solved it by creating another action method just like the first one (added one extra character) and now it works.
I have a problem in iOS7 where I am calling a segue with performSegueWithIdentifier (I have code just like this that works just about everywhere else), then I log the segue in prepareForSegue, then I log again the view controller (VC) that the segue is supposed to push to the top.
prepareForSegue gets called appropriately and the segue has the correct string as its identifier property. Yet the VC that it is supposed to push to the top never gets initialized nor viewWillAppear gets called.
The segue I am talking about, which is the only one that does not work (all the other ones work in both ios6 and 7), is the one leading form the center VC to the right VC. By the way, this works flawlessly in iOS6.
What could be the cause?
the code:
-(IBAction)gotoMainMenu:(id)sender{
DLog(#"DifferentName");
[self performSegueWithIdentifier:#"DifferentName" sender:self];
}
Get in the habit of not wiring up segue's to buttons. Wire them up to the VC and then in the touchUpInside action, fire off the performSegueWithIdentifier.
I had the same issue and solved it as follows. In view A I had a segue that was triggered by a button (UIButton) and the button was also connected to an action in my controller. When I clicked the button in View A, View B would appear as expected. However, when I tried clicking a button in View B to go to View C nothing happened just as you described above.
In my case the issue was resolved in View A. I removed the segue that was tied to the button and let the IBAction that was associated with the button handle calling the performSegueWithIdentifier, then I created a new manual segue that was only tied to the view and voila things worked as expected again.
In short, I guess make sure you don't have both and action and a segue linked to the same button. Hope this helps.
After struggling for days on firing a segue conditionally, I managed to solve it thanks to Simon's answer here. Please take a moment to have a look or you might not understand what I'm talking about below. I didn't copy paste his answer because he's already explained it nicely over there.
Now I've faced a new question. What if I have multiple View Controllers that I want to segue to from one View Controller?
To explain it further : Say I have one MainViewController with 2 buttons. When clicked upon each button, it should segue to their respective View Controller. First button to FirstViewController and the second button to SecondViewController.
The method described in Simon's answer can be used when you segue from one View Controller to another View Controller. Since in that method, you tie the segue to the View Controller itsrlf and not to the button, you have only one segue with an identifier for that particular View Controller. Therefore I cannot distinguish between the button taps separately.
Is there a workaround to solve this problem?
Thank you.
It might be bit premature to say this but I guess you should look into Segue more deeply.
Yes you can perform segure from button. Just control click the button and drag the cursor to view controller you want it SEGUE'd. And from my understanding only condition there is each button tap results a segue to a fixed view. There is no condition there.
Also, you can push the navigation controller manually by
YourViewController *destViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"YourDestinationViewId"];
[self.navigationController pushViewController:destViewController animated:YES];
UPDATE:
prepareForSegue is too late to stop a segue from proceeding. Yes you can create multiple segues from your view to other view controllers. And in this case you have to do so. Don't reate a segue from button, just define a IBACtion on the button click you can do the validation from there,
if(validationSuccess) {
[self performSegueWithIdentifier:#"segue1" sender:self];
}
if you are using ios6
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
return YES on validation success and NO on failure to stop it from proceeding.
I suggest you look a bit at reworking your code logic.
If I understand correctly, you have a VC (embedded in a Nav. Controller) with 2 buttons and you have figured out how to segue each button to a different VC.
Your problem is you want to make sure that even if one of the buttons are pressed, a validation is done before an action takes place. I would advise this is bad User Interface design because the user has the illusion that this button might do something and then they click it and nothing happens.
UIButton can be connected to IBActions (to initiate actions) and IBOutlets (to set their properties). If this is a button created in IB directly, I would connect it to your class as an Outlet property:
#property (nonatomic,weak) IBOutlet UIButton* myButton;
And then set its enabled value:
self.myButton.enabled=NO;
This will keep the button and dim it. This is much better UI design and the user knows they should not press the button because some condition is not satisfied.
I would rework the code so that you set this value as disabled by default for example and enable it appropriately in your code whenever your "condition" is satisfied.
Obviously if this button is created programmatically (in your code without IB) then it is easy to just use the second command above.
Hope this helps.
I just wrote another way to call multiple detail views from a single table. Each cell could essentially make a different view be displayed. The code is similar to what you see in this post but you essentially use identifiers and attributes on the list item to determine which view to show.
https://codebylarry.com/2016/07/15/multiple-detail-views-in-swift/
override func tableView(tableView: UITableView,didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 1 {
self.performSegueWithIdentifier("secondView", sender: self)
} else {
self.performSegueWithIdentifier(“others", sender: self)
}
}