segue not going to destination controller - ios

In my app I have a manually triggered push segue called "details". It is wired from the source controller to the destination controller and it's identifier is set. In my code I call
[self performSegueWithIdentifier:#"details" sender:sender];
I can see the prepareForSegue function firing and have verified that the destination controller is of the proper type. I pass the destination controller a few bits of data it needs to display correctly. Oddly enough NOTHING happens. The app does not go to the destination controller.

Here are some things to look out for if you are having an issue with performSegueWithIdentifier while using a storyboard
You have correctly hooked up your transitions in your Storyboard
Your Segue Identifier matches the one on your Storyboard
Your ViewController's class has not become deallocated
(This can sometimes occur accidentally by calling from another class)
Try setting sender to "self" rather than sender
Also, if you are planning on passing data between ViewControllers it is suggested that you use the prepareForSegue method, allowing you to pass values before segue'ing.

Related

Call storyboard scene without creating a segue in swift?

I created a scene and tried to link the class to the scene and create a segue with the storyboard and use self.performSegueWithIdentifier("SegueID", sender: self) and no matter what I did (i.e. clean build) I still got the same error "reason: 'Receiver () has no segue with identifier 'SegueID''"
I think the best way to solve this is to avoid the segue in this instance all together.
So is there a way to make a call from a view in the code to transition to another view without using segue in swift?
Edit
I've tried all three ways but to no avail. The most common way of just creating a segue between two scenes in storyboard and giving it a name, in my case "Details", but the segue isn't recognized.
So I tried the next way of loading it from a nib and then pushing that nib onto the navigation stack, but when compile and build the program and I click on the button to present to new view controller, nothing happens except for the function println executing.
And trying to use the destination controller manually just didn't work. instantiateViewControllerWithIdentifier expects a string and complains that there are too many arguments in the call
Your code doesn't work because you need to setup a segue in storyboards with a specific ID that you pass as an argument when you call performSegueWithIdentifier. So, in your case, you need to create a segue with ID "SegueID", since that is the string that you are passing to that call.
If you don't want to do this using storyboards, you can still just use UINavigationController directly (after all, a segue uses a UINavigationController under the hood).
Then you just need to instantiate your destination view controller manually (e.g. by using
self.storyboard.instantiateViewControllerWithIdentifier(<your vc id from the storyboard>, animated:true)
or by loading it from a nib
init(nibName:bundle:)
and then push it onto the navigation stack using
self.navigationController.pushViewController(<the formerly instantiaded vc>)

How to wait for a UIViewController to be completely initialized?

I have a custom segue type (overriding init and perform methods of UIStoryboardSegue) and in init method I instantiate the destination view controller(VC). In prepareForSegue method of source VC I call a method of the destination VC that tries to reload the tableView of the destination VC. The problem is that the table view is not always initialized and I SOMETIMES get a nil de-reference error when I call the reloaddata of the tableview.
The question is that how can I wait till the VC is fully initialized and do not get this error?
I am using swift and would appreciate if you write any sample code for the answer in swift.
just make a call on the viewController's view to force its load.
[viewController view]; //will force a loadView if necessary
///then do what you're trying to do..
I think that the best approach in this case is to add a flag property in the destination VC, something like:
var forceReload: Bool
that you set from prepareForSegue in the source VC. This way, you can choose where to actually perform the data reload from the destination VC (for example, in viewDidLoad or viewWillAppear) by simply checking the value of that flag - of course if the flag is true, don't remember to reset it.
If you also need to pass data from the source to the destination VC, use one or more properties declared in the destination and set from the source.

Why isn't my segue being performed?

I have a segue that should take place when one of a number of things happen, so it's called programatically, like so:
- (void)unwindAway
{
NSLog(#"Let's segue");
[self performSegueWithIdentifier:#"mySegue" sender:self];
NSLog(#"We should have just performed the segue");
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Let's do a segue");
}
but the output I get in the console is:
2014-05-29 22:20:30.173 My App[7848:60b] Let's segue
2014-05-29 22:20:30.178 My App[7848:60b] We should have just performed the segue
so as you can see, it's not even calling prepareForSegue.
The segue name is correct - if I give an invalid segue name it errors as you'd expect.
Any ideas?
For unwind segues, prepareForSegue:sender: is called on the view controller that was the source of the segue, in other words the one you're exiting from.
As per Rob's suggestion in the comments I checked the name of the method in the destination View Controller in the segue. It looked right (and was selected in IB rather than typed) but pasting over it and recompiling fixed the problem. Something must have been messed up in the source code of the storyboard, perhaps an artefact of renaming methods.
It's worth noting if anyone has a similar issue that the app won't generate any error if the destination method of a segue isn't found anywhere (I've confirmed this by typing a nonsense method name).
I know that your issue has been fixed, but for future reference I just want to say that similar problems might be caused by the way the unwind process works (zie the technical note link above).
As soon as the segue has been triggered in a certain view controller, its parent (!) view controller is called with the message: viewControllerForUnwindSegueAction:fromViewController:withSender:. The implementation checks if the parent wants to handle the unwind action. If not, it's array with child view controllers is searched for a view controller that wants to handle the action.
My problem was that the unwind action was implemented in a child view controller of a view controller that was embedded in a navigation controller. So, when te segue began, the navigation controller (the parent) was asked: will you handle the action? It returned NO. Then, it's children were asked the same. It returned NO. Because the message isn't sent to a child view controller of a child of the parent view controller, there isn't a view controller that will handle the unwind action and it is aborted without an error message.
My solution was to implement the unwind action in the view controller itself and not in it's child view controller.

Segue transition from table view cell to another view controller works only some arbitrary times - why?

I use three view controllers and on each view controller I put UITableView and UITableViewCell. When I connected from the first view controller's table view cell to another view controller's from within storyboard and ran the simulator, the segue works as expected. However, when I connect from the second view controller's table view cell to the last view controller from within storyboard IN THE EXACTLY SAME WAY as the first one, then for some reasons the transition doesn't work.
If I define didSelectRowAtIndexPath: and within it call [self performSegueWithIdentifier:#"showDetail" sender:self]; in the second view controller's implementation file, the transition can work as expected. I don't care about whether it's storyboard segue or methods defined in my code to perform the transition, as long as the transition does work correctly.
However, I'd still like to know why such inconsistency occurs. As I said, I connected two storyboard in the exactly same way in both cases and checked out attribute inspector and connection inspector, but I don't find any differences between the two connection there.
Also, while the first view controller can perform the transition without the method being defined, when I define it then the transition doesn't work, issuing the following error message:
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
I think I cannot use both approaches (i.e. storyboard segue and method calls) - I just wanted to know what derives the inconsistency here.
I use iOS 7 and Xcode 5.
First of all, if you use push segues, you can't make a push for the second segue if the first segue is modal (unless you embed your second VC in a navigation controller).
Second, make sure de segue identifiers are unique for each segue.
If you ctrl+drag a segue in storyboard, don't call performsegue in code, you just attempt to do the same operation twice. If the segue is in storyboard, in code you should use prepareforsegue delegate.
Another way of doing all of this is not using any segue in storyboard, then in code #didselectrowatindexpath you can instantiate your destination vc using [storyboard instantiateviewcontrolerwithidentifier...], then [self.navigationcontroller pushviewcontroller..] for a push segue or [self presentviewcontroller...] for a modal.
EDIT: Also, when you ctrl+drag, make sure you are dragging from the cell and not from the table.
Self Answer
I finally found out that the issue was not caused in storyboard - it's on the implementation code. Since I have to use UITableViewCellStyleValue1, I cannot use dequeueReusableCellWithIdentifier, and for some reasons the dequeueReusableCellWithIdentifier has to be used in order to make an automatic transition from cell to another view controller from within storyboard only. I checked out that using dequeueReusableCellWithIdentifier and disabling UITableViewCellStyleValue1 temporarily makes it successful to make the transition without didSelectRowAtIndexPath: method being defined.

Segue not calling prepareForSegue

Perhaps I am missing something simple. I added a modal segue from a button to a view controller. I then added some steps to prepareForSegue (and checked I had named the segue correctly). I have done this a few other times with no problem.
Now, when I click the button, the modal window opens, but the prepareForSegue does not fire. I tried putting a log statement in the prepareForSegue before it even checks the description of the label (so theoretically it should fire for any segue). But I get nothing logged.
Any ideas?
Connecting a segue from a button to the next controller is the correct way to connect it, just remember that prepareForSegue: is called on the VC that owns the button not the incoming controller. You get the incoming controller by calling [segue destinationViewController].
Well I found the rookie error I suspected. I duplicated a VC and forgot to set it's class to my new VC class.
Wire up the Segue to the VC not the button. Then in the touchUpInside event, put
[self performSegueWithIdentifier:#"segueid" sender:nil];
I almost always wire the segue up to either the VC or a tableviewcell (if I am using a static cell TV)
You should set cell's reuse identifier set before segue is called.
I tried lots of solutions like above
and checked VC settings
but didn't set the prototype cell's reuse identifier.
Only after I set this to "Cell" , it worked finally.

Resources