I have 3 segues to 3 different views. 2 are implemented with no problem, it is when the third is created that the problems occur.
I have the following didSelectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#" ---------- did select row");
if(indexPath.section == 0){
if(indexPath.row == [self.data count]-1){
//prior to adding this, everything works
[self performSegueWithIdentifier:#"MoreComments" sender:self];
}else{
[self performSegueWithIdentifier:#"FriendView" sender:friend];
}
}else if(indexPath.section == 1){
if(indexPath.row == [self.data2 count]-1){
[self performSegueWithIdentifier:#"MorePosts" sender:self];
}else{
[self performSegueWithIdentifier:#"FriendView" sender:friend];
}
}
}
I have the following prepareForSeque method:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"MorePosts"]){
MorePostsViewController *mfamvc = segue.destinationViewController;
mfamvc.data = self.data;
}else if([segue.identifier isEqualToString:#"FriendView"]){
FriendViewController *fvc = segue.destinationViewController;
fvc.friend = friend;
}else if([segue.identifier isEqualToString:#"MoreComments"]){
MoreCommentsViewController *mcvc = segue.destinationViewController;
mcvc.data = self.data2;
}
}
Before control dragging from my cell to the last view I can see that my program hits didselectrow and then prepareforseque. This makes all the view navigation work perfect.
As soon as I control drag from my cell to the MoreCommentsViewController I start to see the error:
nested push animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
I notice that now also prepareforseque is being called twice, with prepareforseque being called first, then didselectrow, then prepareforsegue again.
What am I doing wrong to conditionally go to these different views?
You should use either didSelectRowAtIndexPath or segues from cell, but not both. If you want your didSelectRowAtIndexPath to invoke segues, those segues should not be from the cell to the next scene, but rather from the view controller icon in the bar above the scene:
You can now select this new segue, go to the "attributes inspector" (option+command+4), and supply a storyboard identifier which you can reference in your code when you call performSegueWithIdentifier.
The reason is you can't drag from a tableview cell to multiple views. As #rdelmar mentioned this is wrong. You should drag from the destination to the source view and then handle manually the way I did above.
Also can be found here: Conditional segue performed on tap on UITableViewCell
Related
I have a problem.
I have a ViewController embed in navigationController.
And use the storyBoard to add the tableView in this viewController.
then,I add the segue.
Finally,I click the cell that the next viewController show twice.
I don't know how to fix it.
Thanks!
This is my code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 2){
[self performSegueWithIdentifier:#"showAdd" sender:self];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"showAdd"]) {
AddCommentViewController *AddCommentVC = segue.destinationViewController;
AddCommentVC.CommentString = _DetailString;
}
}
You have to add the segue between both the UIViewController, not with the cell and UIViewController, as you have connected that segue on click of cell and you are calling the segue manually also that's why it is showing twice.
Do one thing, remove the segue and connect it between UIViewControllers then it will called only once.
With this code every time user click on any cell will perform the segue again and again , I am wondering how could I keep track of the loaded view to keep data when switching views and not an infinite new viewcontroler.
Thanks -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) {
[self.navigationController
performSegueWithIdentifier:#"rep" sender:self];
} else if (indexPath.row == 1) {
[self.navigationController
performSegueWithIdentifier:#"rep1" sender:self];
}
}
Try my other approach first, but if you really need a maintain a pointer to the new view controller you could try this approach. This should perform the segue once, creating the reference to the view controller which will subsequently be manually pushed into the navigation controller.
Override the view controller methods:
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{
if(self.myViewController == nil){
return YES;
}else{
[self.navigationController pushViewController:self.myViewController animated:YES]
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
self.myViewController = (MyViewController*)segue.destinationViewController;
self.myViewController.customVar = 1; //perform initial customization
}
What do I know though, I've never used Storyboards...
Perhaps an alternative to maintaining a reference to the view controller would be to customize the view controller prior to seque.
Override the view controller method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
MyViewController *targetController = (MyViewController*)segue.destinationViewController;
targetController.customVar = 1;
}
The default implementation of this method does nothing. Your view controller overrides this method when it needs to pass relevant data to the new view controller. The segue object describes the transition and includes references to both view controllers involved in the segue.
You don't need to take new View controller each and every time for each row unless and until you want it customized. This will make large amount of view controllers on storyboard.
So, Just command drag segue from controller A to B. Example: if A is tableViewController and B is simple VC where you are displaying data of table's row then command drag from whole tableViewController to B. Now this will act as common segue with one identifier only.
So in your code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Set your B's label/property etc to cell's data or anything so that it will reflect in B.
B.label = cell.text;
[self performSegueWithIdentifier:#"Identifier" sender:self];
}
Hope this helps.
I think you can keep the new viewController's pointer. Then next time you can use it like this:
[self.navigationController pushViewController:thePointer animated:YES]
I very seldom use Storyboard. So I am not sure it will work.
I am getting this error when I try to preform a segue...
2012-11-14 20:24:54.133 MyApp[26266:c07] nested push animation can result in corrupted navigation bar
2012-11-14 20:24:54.486 MyApp[26266:c07] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
2012-11-14 20:24:54.487 MyApp[26266:c07] Unbalanced calls to begin/end appearance transitions for <SheetDrillDownViewController: 0xa1bb980>.
Here is my setup: Initial view --> next view (UITableView) --> last view (UITable)
Each cell pushes to another view until the last view. I do not have a modal segue, i have a push segue... I have the push segues linked from the cell to the next view, each with different names... I have a perform segue line in my selectedRowAtIndex method. I have tried removing that method, with people saying I am double calling the segue, but then the cell when clicked turns blue, and doesn't push to anywhere... How can I fix this error? Thanks.
Here is my code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath) {
[self performSegueWithIdentifier:#"subjectDrillDown" sender:nil];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Attempting to identify segue...");
// Make sure we're referring to the correct segue
if ([[segue identifier] isEqualToString:#"subjectDrillDown"]) {
NSLog(#"Segue has been identified...");
// Get reference to the destination view controller
SubjectDrillDownViewController *vc = [segue destinationViewController];
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
NSMutableDictionary *object = [tableDataSource objectAtIndex:selectedIndex];
NSString *key = [object valueForKey:#"key"];
[vc setSelectedItem:key];
NSLog(#"Switching to %# detail view...",key);
NSLog(#"Passing dictionary to %# view... (Source below)\n\n %#",key,[NSString stringWithFormat:#"%#", [tableDataSource objectAtIndex:selectedIndex]]);
[vc setDetailDataSourceDict:[tableDataSource objectAtIndex:selectedIndex]];
}
else {
NSLog(#"ERROR, DOUBLE CHECK SEGUE'S NAME!");
}
}
I have seen all of the other Stack Overflow questions, but most of the correct answers don't work for me...
EDIT:
The next view is able to load, but when I click the back button, there are suddenly two more views...
UPDATE:
I will try to post the number of times Attempting to identify segue... NSLogs, but my compiler suddenly won't run :(
You surely don't need to perform segue in didSelectRowAtIndexPath, if you have already configured it like cell -> next view.
But, removing the call from there doesn't work for you then you can try the segue from view controller (ctrl+drag from view area) to next view and keep the segue call in didSelectRowAtIndexPath
I always use one of the following methods
Method 1:
Segue from UITableViewCell to Next View Controller
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Nothing
}
Method 2:
Segue from Main View Controller to Next View Controller
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self performSegueWithIdentifier:#"subjectDrillDown" sender:nil];
}
The error you are getting is because you have segue and you perform the segue manually when selected - hence, it is resulting in nested push animation
Make sure the name of the segue is correct and you are using ONLY one of the above methods
I'm new in ios app developping and i'm having some trouble with multiple warnings.
I have a Navigation Controller that load a table view.
From that table view one touch on a cell pushes a new VC (basically, the detail of the cell).
And on that "detailView", when a certain button is pushed, another VC is pushed.
I push the last VC with the following code :
- (IBAction)toMoreDetail:(id)sender
{
[self performSegueWithIdentifier:#"toMoreDetail" sender:self];
}
And when i do that, 2 warnings are poping :
2012-08-05 02:25:41.842 appName[2145:f803] nested push animation can result in corrupted navigation bar
2012-08-05 02:25:42.197 appName[2145:f803] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
I didn't find any good answer so far.
Maybe anyone can help me with this problem.
Thanks :)
Edit : here is the code for the other segue :
From the TableList to the VC of detail (the segue start from the prototype cell and goes to the detail vc) :
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"toDetailEvent"])
{
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
DetailEvent* detailEvent = [segue destinationViewController];
detailEvent.eventToDisplay = [listEvents objectAtIndex:selectedIndex];
}
}
My guess would be your button is linked with the segue, so when you add an IBAction on it, you trigger the segue twice.
If you go to your Storyboard and click on the segue, you should be able to see its origin and destination. Is its origin the entire view controller or just the button? You only need to manually performSegue if the origin is the entire view controller. Can you try comment out your [self performSegueWithIdentifier:#"toMoreDetail" sender:self]; stuff to see if it will work?
It seem that if you use a storyboard and hook up your segue from the source vc to the destination vc and call the segue using didSelectRow you can not leave an else statement for a segue choice:
This works:
if ((indexPath.row == 0 && indexPath.section == 0)) {
[self performSegueWithIdentifier:#"simpleLines" sender:self];
}
if ((indexPath.row == 0 && indexPath.section == 5)) {
[self openAppStore];
}
if (indexPath.section == 4) {
[self performSegueWithIdentifier:#"pushSettingsVC" sender:self];
}
This does not work:
if ((indexPath.row == 0 && indexPath.section == 0)) {
[self performSegueWithIdentifier:#"simpleLines" sender:self];
}
if ((indexPath.row == 0 && indexPath.section == 5)) {
[self openAppStore];
}
else {
[self performSegueWithIdentifier:#"pushSettingsVC" sender:self];
}
You get a weird double push when using navigation controller. I do this every time I start a project and always forget why it happens. Next time I
Hi I have a storyboard and am able to show a detail view when clicking on a table cell. I want to add extra functionality so that depending on what cell I click I show a different view controller. I tried dragging two segues from the same cell but it doesn't allow it.
My thinking was that I would have two segue's from the cell each pointing to a different view and then invoke the desired segue:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = indexPath.row;
NSLog(#"Selected Item :-) %#",[NSString stringWithFormat:#"%#",[myData objectAtIndex:row]]);
if(row %2 ==0){
NSLog(#"Even");
[self performSegueWithIdentifier:#"ShowSecondIndex" sender:self];
}else{
[self performSegueWithIdentifier:#"ShowSelectedMovie" sender:self];
NSLog(#"Odd");
}
}
I would then handle the segue in prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Prepare For Segue ID:%#",[segue identifier]);
if([[segue identifier] isEqualToString:#"ShowSelectedMovie"]){
Tab2_ItemViewController *vc = [segue destinationViewController];
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
NSLog(#"Selected Index: %d",selectedIndex);
[vc setSelectedItem: [NSString stringWithFormat:#"%#",[myData objectAtIndex:selectedIndex]]];
NSLog(#"String Value: %#",[NSString stringWithFormat:#"%#",[myData objectAtIndex:selectedIndex]]);
[vc setSelectedIndex:selectedIndex];
}else if([[segue identifier] isEqualToString:#"ShowSecondIndex"]){
NSLog(#"Viewing Second Index");
}
}
However it never shows the second view. Is this because its not possible to have two segues from a single table cell. I also tried dragging both segue's from the controller to each destination rather than one from the cell and one from the controller but sill no luck???
Don't try to hook up the Segues to a tableviewcell in this case. Hook them up to the View Controller itself.
Don't try to create multiple segues from a TableCell to other view controllers, you want to ctrl+drag from the view controller icon below the view controller in the storyboard interface to the viewcontrollers you want to segue to. Then it will allow you to set up multiple segues.
and then to actually make the segues work, you need to add identifiers to the segues themselves, which you can do by clicking on them and then giving it a name in the property inspector:
then, for the example of TableCells, in your UITableViewDelegate, in
-tableView:didSelectRowAtIndexPath:
you can use
- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender
to manually start a segue depending on your own logic of what segue should be chosen.
Here's a sample code from my demo project:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *segueName = nil;
if (type == kCore) {
segueName = #"segue1";
} else if (type == kStdlib) {
segueName = #"segue2";
}
[self performSegueWithIdentifier: segueName sender: self];
}
type is a property of view controller, which determines which segue should be performed.
As the above answer said, the key is to create segue by linking two view controllers.
In swift 3.1, with a segment control of two states
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var segue: String!
if selectedSegment == 0 {
segue = "segue1"
} else {
segue = "segue2"
}
self.performSegue(withIdentifier: segue, sender: self)
}