prepareForSegue not called in embedded segue - ios

I have a table view controller embedded in a container in a view controller.
In both the view and table view controllers prepareForSegue method I put NSLog(#"name of the controller")
I see a log for the view controller but not the table view controller. Shouldn't I also see the nslog for my table view's prepareForSegue?

Exactly - as Greg explains, the embed type of segue is
only called during setup!
This is very confusing. You could say that
"prepareForSegue" is A REALLY BAD NAME!
the name "prepare for segue" only makes sense in the (rare!) case where you are actually "segueing" from one scene to another
In an iOS app container views are commonplace, you have them everywhere, whereas you rarely use an actual "scene segue".
So really, "prepareForSegue" should be called something like:
"Hey, we're setting up all your container views -- you can grab any info you need at this time! Oh, if you happen to be doing a scene segue, you can use this also!"
what about:
containerViewBeingSetUpOhAndAlsoPrepareForSegueIfYouHappenToBeDoingThat:
That's a bit long, but clearer!
It's just one of those weird things about iOS that you have to know, but is never explained anywhere.
Here's a full explanation of using container views for beginners https://stackoverflow.com/a/23403979/294884

In Your Log Frame View Controller prepareForSegue will be called directly after initWithCoder: to prepare your TableViewController. I cannot see your connection between table view controller and another view (view on the right) but I believe it will be called when you hit the row.
//EXTENDED
The other thing could be that you haven't add UINavigationController on the view hierarchy and you set up your segue style to 'push'. Try change style of your segue to 'modal' in attribute inspector.
Hope this help.

Other than what's already discussed, you should make sure you aren't ignoring segue identifier in following delegate call.
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender

Related

Pass values to previous view controller in a navigationviewcontroller stack

In UINavigationViewController, if I wanna pass values from one controller to next, just call - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender , but what should I do if I wanna pass values from one viewController to previous viewController
I remember running across this same issue a few projects back. I can't find the my code to answer this question, but I did find a few tutorials.
http://prateekvjoshi.com/2014/02/16/ios-app-passing-data-between-view-controllers/
http://www.infragistics.com/community/blogs/torrey-betts/archive/2014/05/29/passing-data-between-view-controllers-ios-obj-c.aspx
and hence the concept of delegate came forth from segues.
Basically Segues are transition from one view to another but the child view is over the parent view, (inside a stack) so the parent view is still loaded.
So if u put segues everywhere and pass values between them then objects will keep on be creating and stored inside a stack and thus the cycle carries on.
So delegates was introduced.
Delegate is a method by which a child view controller(the later one) sends information using the inbuild delegate methods or self created protocol methods to the Previous view controller(the first one).
Here the one sending the information(later view) declares a delegate object, and a delegate method.
Which is then implemented by the recieving class(first view). So even after the later view is popped from the stack, the information is sent back to the root view by the delegate method.
Go through the documentation, its given in a more appropriate way
Hope this helps
Set previous view controller as delegate of current view controller and pass any values you want. This is standard approach.

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.

Add parameters to TabBar Storyboard segue

I have a TabBar with 3 buttons, the 2nd and 3nd buttons have a segue to the same controller, which should show different info depending on one param.
I've overridden TabBar class to implement.-
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
to be able to add my param just before performing the segue, but I must be missing something obvious because prepareForSegue is not getting called.
Is there anyway to achieve this without programmatically creating custom segues?
According to me you cannot interact with segue linked as "root" controllers.
Those segue are not "getting called" as they don't represent a transition between two view controllers.
If you look at Interface Builder there is no settings available for that kind of segue.
I had a similar issue in one of my project and solve the issue by setting the controllers programmatically. After that you add your view controller in storyboard and set a "Storyboard ID" in the right hand panel.
Then, you can instantiate your view controller by doing
[self.storyboard instantiateViewControllerWithIdentifier:#"YOUR_VIEW_CONTROLLER_ID"];
And affect them to your UITabBarController by doing
[self setViewControllers:viewControllers];
Hope this help!
Not sure if it's the best practice, but I finally ended up getting the selected tab from my controllers.-
self.tabBarController.selectedIndex
This simple way, I know what info should I show, without changing my storyboard segues.

Pop the current view using Segues/Storyboard on iOS 5

I am creating an app using iOS 5 SDK. I managed to push views using the Storyboard's Segues, but I cannot find the proper way to pop the current view and go back to the previous one.
I am not using any navigationController (the app doesn't have any top or bottom bars).
I don't think using modal or push segue the other way would be the solution as it instantiates a new controller.
Do I have to use a custom Segue with the opposite animation and deletion of the view at the end ? Or is there a better way ?
Storyboards in iOS 5 don't provide a "no-code" way to return from a segue -- that's something you'll need to implement yourself.
If you use "push" segues (which require a navigation controller), use the navigation controller's popViewControllerAnimated: method to undo the last push segue. (Or other methods to undo more; see the UINavigationController documentation.)
If you use "modal" segues, call dismissViewControllerAnimated:completion: on the view controller which presented the current view controller (which you can get from its presentingViewController property).
Update: In iOS 6 and later there's unwind segues for going "back" in a storyboard. It's still not a no-code solution -- and it shouldn't be, because you need to be able to do things like differentiating between "Done" and "Cancel" exits from a modal view controller. But it does let you put more of the semantic flow of your app into the storyboard. Apple has a tech note that describes them in detail, and they're also covered in the video from WWDC 2012 Session 407.
You could try calling [self dismissViewControllerAnimated:YES completion:nil]; from the controller you want to dismiss (whether the controller has been pushed, or shown modally).
Here is the related documentation : UIViewController Class Reference
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.
Just to clarify.
In the class that was pushed. Simply wire up the following and the controller and view will be popped off.
[self.navigationController popViewControllerAnimated:YES];
Create Segue type "Custom" on your stroyboard. This can be from a button.
Create a new UIStoryboardSegue class named "popSegue"
In the popSegue.m file add the following;
-(void)perform{
UIViewController *sourceViewContreoller = [self sourceViewController];
[sourceViewContreoller.navigationController popViewControllerAnimated:YES];
}
-In the storyboard editor.
-Select the segue and change the Segue Class to "popSegue"
-Set the Identifier to "popSegue"
Done!
You can use the same "popSegue" class throughout your project.
Hope this helps
I'm using Xcode 5 also and here's how it's done. First, in the view code file that pushed the other, create an IBAction method in the .h file such as this:
- (IBAction)exitToHere:(UIStoryboardPopoverSegue *)segue sender:(id)sender;
Then in the .m file add this:
- (IBAction)exitToHere:(UIStoryboardPopoverSegue *)segue sender:(id)sender {
}
You can add any cleanup code you want executed in this method. Next go to your storyboard and select the pushed view. I assume you've got some kind of button on the view that the user taps to signal he's finished. Click on that button, hold down the key and drag to the the green box below the view which is the Exit. Release the mouse button but continue to hold the key. A popup will appear and your method will show in the list. Select that method. Now when the user clicks on the button, the view will pop and you'll be returned to the starting method.

Resources