Cancelling a modal view crashes the app -- Seeking Solution - iphone

My app is crashing when I am trying to dismiss a modal view using:
[self dismissModalViewControllerAnimated:NO];
This is the flow of the application:
ViewController (My app landing screen) --> Push couple of view controllers --> Show the modal view.
Now, is my intention of canceling the modal view from the same modal controller (self) is correct or should I cancel it from somewhere else.
I had tried passing the object of the last conroller class in the stack to my modal controller and tried following code but it still crashes:
[self.lastStackObj dismissModalViewControllerAnimated:NO];
Appreciate if someone can guide!!!

try this :
[self.parentViewController dismissModalViewControllerAnimated:NO];

maybe you're releasing an already released object in the dealloc.
try commenting all the release statements in the dealloc & then try running, hopefully it wont crash.
You can fix it by finding the variable & releasing it only once.
There maybe other problems causing this too. But this is the first thing i'd look for.

Related

Automatically dismiss underling modal view

I'm sharing this as it took me A while to figure out. This is if you need to get rid of a double stack of modal views IF it is pressent.
if(self.parentViewController.parentViewController)
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];
else
[self dismissModalViewControllerAnimated:YES];
I have a view that sometimes gets called from a modal view. In that case I would need to get rid of both views at the same time. While dealing with the situation where it was the only modal view. This worked.
As of xCode 4.2 this is no longer working, The new way to deal with this situation is:
if(self.presentingViewController.presentingViewController)
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES];
else
[self dismissModalViewControllerAnimated:YES];
As pointed out by #Hollance in a relevant thread of mine:
iOS 5 SDK treating UIViews differently
"There is a new property in iOS 5 named presentingViewController. The meaning of parentViewController got changed a bit with the new container view controller API, so it may not always be set when you think it is. That's what presentingViewController is now for."

Releasing UIViewController when not in use

Hi I hope somebody can help me with this problem.
I have a UIViewController named "Login" (for example) and when the user has successfully logged in this will call another controller to replace the "Login" controller like below:
[self presentModalViewController:anotherController animated:YES].
I do not need the previous controller any more so I placed a [self release] as shown in the code snippet below.
LoginController.m
- (void)viewDidDisappear:(BOOL)animated {
[self release];
}
This will then call the LoginController's dealloc method and I can be sure it's released.
Now in the new controller that is now in view has a button which calls a UINavigationController like below:
[self presentModalViewController:settingsNavigationController animated:YES];
But this crashes the app which would normally work if I didn't release the previous LoginController.
There is probably an easier or more logical method to release the controller but as I am running out of ideas I sometimes use drastic measures.
Thank you.
You should not be releasing the LoginController, at least not in its own -viewDidDisappear:. That controller is still in use and can be referenced, for example by the navigation controller's parentViewController property. Release the controller when it is no longer part of your view controller hierarchy, not just when it is no longer visible.
In addition [self release] is a warning sign that you are applying incorrect memory management.
1) Replace the "Login" controller
presentModalViewController doesn't replace your login view controller, but it puts anotherController on top of your login view controller.
2) viewDidDisappear
You should read documentation. Quote - You can override this method to perform additional tasks associated with dismissing or hiding the view. If you override this method, you must call super at some point in your implementation.
In other words, you must call [super viewDidDisappear:animated] too.
3) Memory Management
You should definitely need to read Memory Management Guide - http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/MemoryMgmt.html
4) View Controller
You should definitely need to read View Controller Programming Guide too - http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
Two problems with what you are doing.
First, viewDidDisappear is NOT a destructor. Do not release self there. viewDidDisAppear and appear are used for visibility of the view, not in/out of memory.
Second, presentModalViewController is intended for presenting a MODAL view controller, ie child.
You should consider setting up a UINavigationController and calling
[navigationController popToRootViewControllerAnimated:FALSE];
[navigationController pushViewController:(UIViewController*)controller animated:TRUE];
also in some situations you can get away with an [autorelease] view controller using present modal.

iPhone - error loading view controller

I load view controllers all the time in the following format:
-(void)loadSelectUser {
MyViewController *nextController = [[MyViewController alloc] initWithStyle:UITableViewStyleGrouped];
MyAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
[delegate.navigationController pushViewController:nextController animated:YES];
[nextController release];
}
And I've never had an issue with that. But right now I'm dealing with the issue that the next view doesn't load completely. The navigation bar shows up and the viewDidLoad and the numberOfSectionsInTableView methods are both called. That is it. The table doesn't show up, it still shows the previous view.
I imagine this means there is a memory leak or something not connected properly. Is this the right path to be looking? If so, what is your best suggestion for debugging this issue. My code has no error messages so I'm not sure where to start. I load the view properly in a different controller, but for some reason it doesn't do it after this particular view*.
*This view happens to do a lot data manipulation with downloading objects, saving them and such. But again, it looks like it is all working properly. What would mess up the navigation controller loading the next view completely?
Oh, and just to mess things up more, some times, it works properly. But I run it one more time and it doesn't do it again.
Update: TechZen comment about the proper way to push a new view controller seemed to help a little. There is a higher rate of it working, unless I am pushing a tableviewcontroller. Depending on the action my view will push a UITableViewController or a UIViewController with a nib file. The second usually (not always) works.
Also, in a different view I am adding a modal view. But when I try to dismiss it using [self dismissModalViewControllerAnimated:YES]; it doesn't always work. Again it's hit or miss on it. Anyone have an idea of what would be causing the transition of windows to be finicky?
Calling the app delegate to get the navigation controller is unnecessary and risky. Any view controller on a navigation controller stack has a populated navigationController property so you can just use self.navigationController.
It's risky to call the app delegate's navigation controller because you have no guarantee that you will get the same navigation controller as the one that currently holds the view controller calling the push. You could in theory end up with two overlapping and conflict navigation controllers.
Switch the code to self.navigationController and see if that fixes the problem.

dismissModalViewControllerAnimated: crashes in Simulator but not on phone

I'm doing the following:
[self.parentViewController dismissModalViewControllerAnimated:YES]
This code fails using the Simulator but works with no issues on the phone itself. The Simulator's console shows no erros. I used NSLog statements to pinpoint this line of code as the culprit. When running on the phone, however, the console(window>organizer) shows that the above code is executed and the application proceeds forward with no problem.
When running the code in debugger, the following statement appears at the bottom of the Xcode debug window:
GDB: Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
Then a window dispalys stating: Loading 43672 stack frames. (that sounds bad)
In the debug window the following line appears numerous times:
[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]
Without getting too deep into my code, does anyone know about or have experience with this type of condition?
Thanks
Why you don't just call [self dismissModalViewControllerAnimated:YES]. It is quite enough to close you modal view controller.
I know, it isn't answer for your question, but maybe it helps to avoid your issue.
I think where you are calling this from is key but you don't say where this code is.
I suspect that dismissing your parentVC is causing this code to get executed again, which tries to dismiss the parent again... basically an infinite loop.
Thanks for the responses.
Aleksejs - I've tried your suggestion with no success. Thanks for making sure I've done the obvious first.
progrmr - I think you are probably correct - when and where I dismiss the modal view is the key and I'll look into how I'm doing this. I may need to re-architect how I'm handling my views.
This is frustrating because the issue does not happen on the iphone itself, only in the Simulator. And, I just confirmed that with the same MacBook Pro the error does not present itself in the Simulator when I'm working from home - the problem only occurs at my office. Strange, eh?
I'll keep digging and report my findings.
Thanks again.
Update - I didn't solve the problem but instead avoided it by re-structuring things. Before, in applicationDidFinishLaunching:, I presented a Login view controller as a modal view. I then need to display a EULA view controller so the user can agree to some legal stuff. I think my problem was that I was presenting the EULA view as a modal from the Login view (which is also modal). The order in which the modals were being presented/dismissed, I think, was the problem (as progrmr had suspected).
How I avoided the issue? I took the time to learn about the delegation pattern. Now, each modal view (Login and EULA) are presented within the app delegate class and I use delegates to callback when certain actions are taken on the modal views.
You shouldn't use self dismissModalViewControllerAnimated if self doesn't actually have a modalViewController. Just create a protocol that delegates the dismiss from the modal view controller back to the parent. when you push the modal view controller, assign the delegate, then when you want to dismiss it call [self.delegate dismissMe] which in turn calls [self dismissModalViewControllerAnimated:...] on the delegate (the parent).
[[Picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
Instead of
[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];
and
[self presentViewController:picker animated:YES completion:nil];
Instead of
[self presentModalViewController:picker animated:YES];

popToRootViewController crashing

I am a relatively new iPhone app developer so my knowledge is a little sketchy, so please forgive me if this is a bit of a trivial question.
I have a navigation app which drills between table views by calling pushViewController on the navigationController object
I have one particular section which pushes new view controllers sequentially as the user goes through the interface. The view controllers are all subclassed from UIViewController.
It all works fine until it gets to the end, where the idea is the user presses a "Finish" button and is returned to the root view controller (main menu).
So on the button press I call:
[[self navigationController] popToRootViewControllerAnimated:YES];
And it crashes.
I am a bit worried this could be a big problem as this definitly worked at some point but it is now always failing.
Can anyone give any ideas/advice?
Some suggestions:
Before calling popToRootViewControllerAnimated: confirm that the RootViewController does actually exist. If it died somewhere along the line, calling the method will cause a crash.
Check the – viewWillDisappear: and – viewDidDisappear: methods of your last view to make sure you're not doing something dangerous there.
Not sure if popping a view causes it to always deallocate but check the dealloc method of the views and their controllers to make sure your not over-releasing something.
One mistake I've seen a lot is releasing objects in the data model from controllers. When another controller (in this case the RootViewController) tries to access the data model the app crashes.
It sound's like you need how to use the Xcode debugger. Type in debugger in Xcode help to get pointers.
You should not be using popToRootViewController in your viewWillDisappear.
Instead if you want to pop to root controller on your pressing the back button, you should replace the back button by your own and add an action to it. Try doing something like ::
UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithTitle:#"back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(goBack:)];
self.navigationItem.leftBarButtonItem = back;
and then handle the action as ::
- (void) goBack:(id)sender
{
// pop to root view controller
[self.navigationController popToRootViewControllerAnimated:YES];
}
As the others have commented, the first step is to run this is debug mode and figure out where and why you are crashing.
The most common type of crash is using a deallocated object (EXEC_BAD_ACCESS). Have you run the static analyzer? Are you properly retaining your object references?