iPhone SDK: Switching to one view then back to previous view errors - iphone

I have a UITabBarConroller that I use to switch between 3 different views. This all works perfectly. On one of my tabs, I added a button at the to called "Add", I have added an outlet to this, as well as an IBAction method which looks like the following:
// Method used to load up view where we can add a new ride
- (IBAction)showAddNewRideView {
MyRidesViewController *controller = [[MyRidesViewController alloc] initWithNibName:#"AddNewRide" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}//end showAddNewRideView
This currently works fine, and loads up my AddNewRide nib file. But, once that view loads, I have a cancel button, which, when clicked, I want to return to the previous view. So, I figured I would just do the reverse of the above, using the following method which would load back my previous nib:
- (IBAction)cancelAddingNewRide {
MyRidesViewController *controller = [[MyRidesViewController alloc] initWithNibName:#"MainWindow" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}//end cancelAddingNewRide
But, which trying to load the MainWindow nib, the program crashes, and I get the following error:
2010-05-05 20:24:37.211 Ride[6032:207] *** -[MyRidesViewController cancelAddingNewRide]: unrecognized selector sent to instance 0x501e450
2010-05-05 20:24:37.213 Ride[6032:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[MyRidesViewController cancelAddingNewRide]: unrecognized selector sent to instance 0x501e450'
So, I am a little lost as to why it would work one way, but not the other.

First, I wanted to address part of the error: Think of your views as a stack. When you "push" a modal controller, you are adding that view to a stack. The old view is still there underneath. So you need to "pop" off the modal view to return to the old view. If you push a new view on, you now have 3 views on the stack which are all taking up memory, where you really only need one.
So, inside cancelAddingNewRide just try:
[super dismissModalViewControllerAnimated:true];
You may have other issues that are causing the crash, but this should generally get things working.

Typically when I have used presentModalViewController the presented viewController tells the calling viewController to dismiss it using dismissModalViewControllerAnimated:YES;
So in other words in the cacncelAddingNewRide you simply call the class that hass showAddnewRideView in it and have it pass itself to the method.
It's hard to explain but I'll show you an example:
cancelAddingNewRide class:
- (IBACtion)home:(id)sender {
if (self.delegate respondsToSelctor:#selector(dismiss:)]) {
[self.delegate dismiss:self];
}
}
and then in the showAddNewRideView class
-(void) dismiss:(cancelAddingNewRide_class *) controller {
[self dismissModalViewControllerAnimated:Yes];
}
Hope that makes sense and soz for typos
Edit: oh and make the controller's delegate self
controller.delegate = self;
Actually thinking about it more there is a bit more to this. You have to define the called viewController as a Delegate. Have a look at Stanford universities iPhone lectures, lecture 11 deals with this and is available from iTunesU.

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];
}

Swapping views inside a tabview controller

I have an app based on a tabBar controller. Within a certain view I'd like to add swipe gesture recognition and swap the current view with another one (which is not part of the tabBarController array). I have tried:
- (IBAction)swipeLeftDetected:(UIGestureRecognizer *)sender
{
//Does not work
UIViewController *DesiredViewController =[[UIViewController alloc] initWithNibName:#"DesiredViewController" bundle:nil];
DesiredViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:DesiredViewController animated:YES];
[self.view addSubview:DesiredViewController.view];
}
but the program crashes. The error I get is related to a SegmentedControl which is present in the next view but is absent in the current one. The views independently work perfectly!
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason:'[<UIViewController 0xa355fb0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key X_SegmentedControl.'
I don't understand what I am doing wrong.. I want to swap the views completely rather than putting one on top of each other. Any advice please? Thanks
instead use this
-(IBAction)swipeLeftDetected:(UIGestureRecognizer *)sender
{
DesiredViewController *objView =[[DesiredViewController alloc]initWithNibName:#"DesiredViewController" bundle:nil];
objView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:objView animated:YES];
[objView release]; // use release if using Non-ARC
}
The problem is not about the transition.
You are loading a view controller from a NIB.
A view controller is usually subclassed, so (assuming that your nib is configured correctly and you have .h and .m implementation file for your DesiredViewController subclass) you should init like this:
DesiredViewController *controllerInstance =[[DesiredViewController alloc] initWithNibName:#"DesiredViewController" bundle:nil];
The exception is because you probably have a segmented control inside your view controller subclass, Xcode is trying to link this control to the outlet on the view controller, but this outlet doesn't exists (because you are allocating an UIViewController not the subclass).

Cannot push TTTableViewController onto Navigation Controller

I have an app where I have a TTTableView Controller inside a Navigation Controller that is Insider a TabBar.
I want it so that if a user selects an item it will push another TTTableView with the items under that category.
The code I have is
-(void)didSelectObject:(id)object atIndexPath:(NSIndexPath *)indexPath {
if ([object isKindOfClass:[TTTableMoreButton class]]) {
[super didSelectObject:object atIndexPath:indexPath];
} else {
CategoryViewController *viewController = [[CategoryViewController alloc] initWithNibName:#"CategoryViewController" bundle:nil];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
}
The CategoryViewController is setup as
#interface CategoryViewController : TTTableViewController
and the CategoryViewController.xib file has the datasource & delegate set to the files owner and the view set to the tableview and the tableview class is set to TTTableView.
When I run it I get the following error when selecting a row
2011-10-17 16:18:23.819 Biz Insider[34067:f803] -[CategoryViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x6c93d30
2011-10-17 16:18:23.820 Biz Insider[34067:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CategoryViewController tableView:numberOfRowsInSection:]: unrecognized selector sent to instance 0x6c93d30'
*** First throw call stack:
(0x1893052 0x157ed0a 0x1894ced 0x17f9f00 0x17f9ce2 0xb4cf2b 0xb4f722 0x9ff7c7 0x9ff2c1 0x9b61e 0xa0228c 0xa06783 0x9bb48 0x9b1301 0x1894e72 0x89192d 0x89b827 0x821fa7 0x823ea6 0x823580 0x18679ce 0x17fe670 0x17ca4f6 0x17c9db4 0x17c9ccb 0x1f88879 0x1f8893e 0x972a9b 0x273d 0x26b5)
terminate called throwing an exceptionCurrent language: auto; currently objective-c
If I try and push another view (i have one with a webview on it) then it works fine, or if I go into interface builder and link the File Owner's "tableView" to the TTTableView object it will work fine and push the controller except the "Pull down to refresh" function wont work so I am assuming that the deletage isn't correct when doing it that way.
Any help would be greatly appreciated.
EDIT:
I have a feeling that it has something to do with the following
-(id<UITableViewDelegate>)createDelegate {
return [[[TTTableViewDragRefreshDelegate alloc] initWithController:self] autorelease];
}
This sets the delegate to TTTableViewDragRefreshDelegate which implements the numberOfRowsInSection and all that junk. Is there another way to do this?
Cheers,
Dean
The log says that in your custom class CategoryViewController method tableView:numberOfRowsInSection: is not implemented and so it couldn't call it.
Check it and check types of its parameters.
Well this is an odd one, but I changed it from
CategoryViewController *viewController = [[CategoryViewController alloc] initWithNibName:#"CategoryViewController" bundle:nil];
to
CategoryViewController *viewController = [[CategoryViewController alloc] init];
and it magically works now...dont ask me how or why.
There must have been something in the NIB that was messing it up, but I dont know how the whole layout is working now with no NIB.

How to properly display a new view and how to go back to the previous view

I'm very new to iPhone development and Objective-C. Today, I figured out how to open a new ViewController and how to return to the previous one.
Here's how I currently do this:
// In the main view controller I have a method called openSecondView that is defined like this:
- (void) openSecondView:(id)sender {
SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:secondView animated:YES];
}
// In the SecondViewController I have a back button that calls a method called closeView that is defined like this:
- (void)closeView:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
My question is, how do you do properly accomplish this?
Should I call [secondView release] after calling presentModalViewController or is this done some what behind the scenes? I ask this because when I was debugging I noticed that presentModalViewController doesn't seem to be a blocking code, the next few lines of code I added seem to execute immediately, without calling dismissModalViewControllerAnimated. Are there any consequences of calling [secondView release] after presentModalViewController?
Any help/advise would be much appreciated.
Just call [secondView release] after calling presentModalViewController. The view controller will be retained until it is dismissed.

iPhone - unrecognized selector sent to instance - Trying to open the starting view after viewing several other views

I am just starting with iPhone programming. I used the utility application project template. A button on the main view of the utility application calls another view which shows some data. At the end of the presentation of the data a "end" view is shown. The "end" view contains a button to return to the main view. This all works great, however once you return to the mainview and try either to click the info button or click the button to call the data view the application terminates with the following error:
-[TheEVController startS]: unrecognized selector sent to instance 0x3933d90
EVController.m
- (IBAction)done {
EVController *controller = [[EV alloc] initWithNibName:#"MainView" bundle:nil]; //controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
}
MainViewController.m
- (IBAction)startS {
SVController *controller = [[SVController alloc] initWithNibName:#"SView" bundle:nil]; controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
[controller release];
}
Any suggestions?
If you want to call startS, which is a method on a MainViewController object, you can't call it on an EVController object.
[TheEVController startS];
tells the Objective-C runtime that you want to invoke the startS method in the TheEVController's class (or one of its parent classes).
It's not entirely clear from the code you posted (you didn't actually show us the section of code that is causing the exception) but from your description it sounds like you're overwriting a UIView variable that initially points to your MainViewController with a pointer to an EVController, and not resetting that variable when you show your MainViewController again.