Pop to root then perform segue on iPhone - iphone

I am running on iOS 6.0 storyboard enabled
I have a NavController linked to a TableViewController.
This TableView can segue to AViewController or BViewController.
When I am in A, I want to pop back to the root and perform segue to B with this line :
UINavigationController *nav = self.navigationController;
[nav popToRootViewControllerAnimated:YES];
[nav performSegueWithIdentifier:#"GoToB" sender:self];
I checked the storyboard, GoToB do exist and is linked from the TableViewController to BViewController
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<NavMainViewController: 0xb921fa0>) has no segue with identifier 'GoToB''
What am I missing ?

The segue will be attached to the view controller you pop to, not nav which is the container view controller that contains it. So this would be closer:
UINavigationController *nav = self.navigationController;
[nav popToRootViewControllerAnimated:YES];
UIViewController *rootVC = [nav.viewControllers objectAtIndex:0];
[rootVC performSegueWithIdentifier:#"GoToB" sender:self];
But, I think the problem here will be that the pop animation will conflict with the segue. Doing the pop with ...Animated:NO might fix it, but I think it would be more correct (and more robust for animations) to perform the segue from the rootVC.
rootVC would implement viewDidAppear as follows:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (!self.isBeingPresented && /* any other condition that makes you want this */) {
[self performSegueWithIdentifier:#"GoToB" sender:self];
}
}

Related

Going back to mapview after having opened a newcontroller from an annotation disclosure button

I am making an application where there are multiple pins in a map. (using xcode for iOS apps) When I click on the pins, the callout comes up with a disclosure button that when pressed brings up a new viewcontroller (which I use as the detail view.. is this correct?)
I am currently having problems going back to the original viewcontroller after viewing the new viewcontroller.
How should I proceed to go back to the map view?
I have tried with the -(IBAction)Back; command and linking it to a button on the new viewcontroller, however when I click it in the simulator, a black screen comes up and no error is shown in the output..
Any help would be appreciated!
I used the following to view the new view controller:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
if ([view.annotation.title isEqualToString:#"..."]) {
...Controller *sampleView = [[...Controller alloc] init];
[self presentModalViewController:sampleView animated:YES];
}
if ([view.annotation.title isEqualToString:#"..."]){
...ViewController *sampleView = [[...ViewController alloc] init];
[self presentModalViewController:sampleView animated:YES];
}
}
EDIT 1:
This is the error code I get after making the change..
2013-06-30 18:02:30.386 lam[15156:13d03] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "...Controller" nib but the view outlet was not set.'
*** First throw call stack:
(0x1e2d012 0x126ae7e 0x1e2cdeb 0xf88c8 0xf8dc8 0xf8ff8 0xf9232 0x104c25 0x3043a3 0x101ee3 0x102167 0xfee0071 0x374c 0x10deb1a 0x10ea28e 0x82f617f 0x127e705 0x1b2c0 0x1b258 0xdc021 0xdc57f 0xdb6e8 0x4acef 0x4af02 0x28d4a 0x1a698 0x1d88df9 0x1db0f3f 0x1db096f 0x1dd3734 0x1dd2f44 0x1dd2e1b 0x1d877e3 0x1d87668 0x17ffc 0x2842 0x2775)
libc++abi.dylib: terminate called throwing an exception
How did your calloutAccessoryControlTapped "bring up" this new view controller?
If you used a modal transition (e.g. such as presentViewController or modal segue), then you would dismiss it with dismissViewControllerAnimated. If you used the deprecated presentModalViewController, then you'd use the dismissModalViewControllerAnimated, but then again, you probably shouldn't use the deprecated methods unless you need to support iOS versions prior to 5.0. Use the presentViewController and dismissViewControllerAnimated renditions, instead. Anyway, you might end up with an IBAction method like:
- (IBAction)handleDoneButton:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
If you used push transition (e.g. pushViewController or push segue), then you'd generally just avail yourself of the built-in "back" button, but if you need your own button to pop this controller, you'd use an IBAction with popViewControllerAnimated. For example:
- (IBAction)handleDoneButton:(id)sender
{
[self.navigationController popViewControllerAnimated:YES completion:nil];
}
Or, if your calloutAccessoryControlTapped used a performSegueWithIdentifier, then you could either use the above technique or, in iOS 6 and above, you could define the following unwind segue in the view controller that has the map:
- (IBAction)backToMap:(UIStoryboardSegue *)segue
{
// do whatever you want
}
And then you can control-drag from the button to the exit outlet in the bar under the scene, and you should see this backToMap unwind segue.
Regarding your error, it means that your NIB's root view is not set. Select the view and look at its outlets. You should see something like:
If not, (a) make sure you set your "File's owner" to be your view controller class; and (b) right click on "File's owner"; (c) drag from the "o" next to the "view" in the popover view to the actual view:
Also, when creating the view controller, you'd probably want to specify which NIB to use:
ViewController *controller;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
controller = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
} else {
controller = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}

How to navigate from Appdelegate to another viewcontroller

In my iPhone app, I am using Pushnotifications. When I receive a notification, I want to move to another viewcontroller from the current viewcontroller. I wrote the - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex in the appdelegate itself. And I am using View based application, so I want to use presentModalViewController (i think). And I used following code:
UIViewController *view = (UIViewController*)self.viewController.presentedViewController;
[view presentModalViewController:self.anotherVC animated:NO];
but got error
2012-06-19 17:47:52.521 iPhoneApp[1450:607] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present a nil modal view controller on target <HomeScreenVC: 0x1fb77cc0>.'
what went wrong here? Any idea.
Edit
I will elaborate the issue:
I have viewcontrollers VC1, VC2, VC3 and VC4. My rootviewcontroller is VC1. If a push notification come when I am at VC2 or VC4, when I click on Ok button of notification alert, I want to move to VC3. But the delegate method for the alert view is in appdelegate.m.
I have updated my code like
self.menuVC = [[MenuScreenVC alloc] initWithNibName:#"MenuScreenVC" bundle:nil];
UIViewController *view = (UIViewController*)self.viewController.presentedViewController;
[view presentModalViewController:self.menuVC animated:NO];
now I can navigate to VC3 if i am at VC2, I can't if i am at VC4. Please help
Instead of what you used do the following
[self.window.rootViewController presentModalViewController:self.anotherVC animated:NO];

iPhone: UITableView delegate is alive after viewController was released

My ViewController1 pushes ViewController2
ViewController2 *controller =
[[ViewController2 alloc] init];
[self.navigationController pushViewController:controller
animated:NO];
[controller release];
ViewController2 has UITableView ... in xib file I connected delegate with File's Owner. Also ViewController2 has Done button
- (IBAction)doneButtonPressed {
[self.navigationController popViewControllerAnimated:NO];
}
The problem is that if to click table rows and done button at the same time, sometimes didSelectRowAtIndexPath: method calls after that ViewController2 was popped, and I have SIGABRT error and this thing in logger :
[__NSCFSet tableView:didSelectRowAtIndexPath:]: unrecognized selector sent to instance 0x62579d0'
So how tableView:didSelectRowAtIndexPath can be called after I popped viewController2 ? It should be dead...
One easy fix is to do this:
- (IBAction)doneButtonPressed {
self.tableView.delegate = nil;
[self.navigationController popViewControllerAnimated:NO];
}
That way you guarantee that while you're leaving that view no more delegate calls will happen. You could also do this in the dealloc method for the view controller (probably a better place for it).
popViewController & pushViewController methods perform their tasks asynchronously. They use an animation block to slide the viewController in and out. The ViewController gets removed from its superview and gets released in the completion portion of the animation block. The crash is because of this delay (I think 0.3 seconds).

don't understand how to use navigation controller in iphone

I'm extremly new to iphone and I have the following misunderstanding.
All over internet the tutorials about how to use NavigationController programatically it says:
NavigationController must be declared in applicationDidFinishLaunching and must be init with a root.After that you can add views to it.
I have this:
A UIViewController class meaning(AdiViewController.h, AdiViewController.m and AdiViewController.xib) and no Delegate file meaning no applicationDidFinishLaunching method.
What I wanna do is from my class-AdiViewController when pressing a button to go to another view.
I understand that I need a NavigationController which should retain my views having the root AdiViewController.
But my problem is where should I initializate that NavigationController in viewDidAppear??...cause I don't have the Delegate files.
If you could provide a minimal example with this small issue of mine it would be great.I'm sure that for those how are senior this is nothing but still I don't get it.Thanks
NavigationController must be declared in applicationDidFinishLaunching -> this is not true.
In your AdiViewController if you have button when you push that button you want to load navigation Controller right ?
// Hook this IBAction to your button in AdiViewController
- (IBAction)pushNavController
{
AnotherViewController* rootView = [[AnotherViewController alloc] initWithNibName:#"Anotherview" bundle:nil];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:rootView];
[rootView release];
[self presentModalViewController:navController animated:YES];
[navController release];
}
If you are in AnotherViewController i.e., you are in root view controller of Navigation controller. You need to push and pop view controllers from there. For example if you have a button in AnotherViewController:
// push next view controller onto navigation controller's stack
- (IBAction)pushNextViewController
{
NextViewController* nextView = [[NextViewController alloc] initWithNibName:#"NextView" bundle:nil];
[self.navigationController pushViewController:nextView animated:YES];
[nextView release];
}
// Similarly if you want to go back to AnotherViewController from NextViewController you just pop that from navigation controller's stack
- (IBAction)pushNextViewController
{
[self.navigationController popViewControllerAnimated:YES];
}

Dismiss ModalView does not work here

So I have a tabBarController as a modalview, and it shows up fine. As I click some of the tabs, the views are loading properly. I want to dismiss the modalView when I click on tabBarController.selectedIndex ==4
So I write in the viewDidLoad and also tried in the viewWillAppear of that view controller to dismissModalViewController and it does not work.
I tried
[self.parentViewController dismissModalViewControllerAnimated:YES];
// ... And also //
[self dismissModalViewControllerAnimated:YES];
Could someone point out why it does not work ?
All you have to do is pass a reference to the modally presented VC pointing on the VC that will present it modally.
Define a weak reference as a property in the UITabBarController subclass, and send a message to dismiss it when required.
For example using a property named mainViewController :
MySubclass *tbController = [[MySubclass ....];
tbController.mainViewController = self;
[self presentModalViewController:tbController animated:YES];
Then in MySubclass define
#property(assign) UIViewController *mainViewController;
and synthesize it, then when the tab you want gets selected :
[self.mainViewController dismissModalViewControllerAnimated:YES];
I think the 4th view controller (of the tab bar controller) is trying to get dismissed by the line
[self.parentViewController dismissModalViewControllerAnimated:YES];
Since this 4th view controller was not presented by any controller, this wont work.
And it is dismissing it's modal view controller by the line
[self dismissModalViewControllerAnimated:YES];
Since, this 4th view controller did not presented any view controller, this again should not work.
You want to dismiss the tab bar controller and not its 4th view controller.
Basically, you can get the reference of tab bar controller from the 4th view controller.
As, [yourFourthViewController.tabBarController.parentViewController dismissModalViewControllerAnimated:YES];
I am guessing this without actually trying. Let me know if this works.
If you have the UINavigationController as the parent controller then the following line will work for you.
[self dismissModalViewControllerAnimated:YES];
But here I think you have the UIViewController is the parent controller instead of the UINavigationController. So, You can do one thing when presentModalViewController.
if(objView == nil)
objView = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];
UINavigationController *navigationController1 = [[UINavigationController alloc] initWithRootViewController:objView];
[self presentModalViewController:navigationController1 animated:YES];
Let me know if you need more help or any questions.