EXC_BAD_ACCESS when popViewController - iphone

I am pushing BViewController from A properly. B contains a webview that starts loading a page when viewDidLoad. I am getting a strange behavior when popping B to A,
If webview finishes its load and then I execute popViewController (IBAction when touchUpInside on a toolbar button), popped to A so everything works perfectly.
However, if I popViewController immediately before webview ends its load, app crashes due to exc_bad_access. why? view is already loaded!
I checked on both situations viewcontrollers that are on navigation stack. Both cases with same result, 2 same objects, no difference!
-(IBAction)goBackOrg:(id)sender{
NSArray *viewControllers = self.navigationController.viewControllers;
[[self navigationController] popViewControllerAnimated:NO];
}
and for previously pushing it, I am using
if(!self.BController){
self.BController = [[BViewController alloc] initWithNibName:#"BViewController" bundle:nil anUrlDest:urlSocial];
}
[[self navigationController] pushViewController:self.BController animated:NO];

EXC_BAD_ACCESS occurs when you're trying to access an object that has been deallocated.
So the following could be your problem: when you pop ViewController B, it is being unloaded. If the web view loading finishes after ViewController B is unloaded, some piece of callback code is getting executed that is trying to do something with your ViewController or its view (or similar).

May be You are loading your webView on Thread and when you are using thread then you cannot do changes in UI otherwise your app will crash.
So just do this task on mainThread .

Related

self.navigationController pushViewController not adding controller to stack

I am on a viewController called vcA and I do this:
[self.navigationController pushViewController:vcB animated:YES];
and it works. vcB is pushed. Inside vcB's viewDidAppear I do this:
NSArray *controllers = self.navigationController.viewControllers;
and controllers contains just one object, vcA !!!! (what?)
Why is vcB being added to the controllers array? Is there anything that can prevent that from happening?
thanks.
I banged my head on the wall for a week to solve this problem involving pushing a view controller on the navigation controller stack.
The problem was this: I was on a navigation controlled based app and I had 3 view controllers, vA, vB and vC.
I was pushing vB from vA using this:
[self.navigationController pushViewController:vB animated:YES];
it worked, but, when I tried to push vC from vB, the self.navigationController property of vB was nil and vB was not on the navigation controller stack. What? Yes, I pushed vB on the navigation stack and vB was not being added to it, but even so, vB was showing correctly.
I discovered that inside vB's viewDidLoad, self.navigationController was not nil and that vB was on the navigation controller stack, but as soon as vB's viewDidLoad ended, vB was removed from the navigation controller stack and its navigationController property was set to nil. At that time, vB was a kind of ghost control, outside the navigation controller stack.
I don't need to mention that from vB I was unable to get back to vA or to push vC.
How that happen?
simple, I was pushing vB from inside a block... something like:
void (^ block1)() = ^(){
[self.navigationController pushViewController:vB animated:YES];
};
What was happening because a UIKit function (the push thing) was being executed in a block that was probably running on a thread that was not the main thread.
The resolution to that was to wrap the push in a dispatch to the main thread, using this:
void (^ block1)() = ^(){
dispatch_async(dispatch_get_main_queue(),
^{
[self.navigationController pushViewController:vB animated:YES];
});
};
The app had another minor problem with a wrong outlet connected to a viewController, but this was the main problem. This is the kind of problem hard to spot, for being subtle. I discovered the problem when I added another button to the navigation bar and that button did not appear. So, I suspect that something involving UIKit was happening, or not happening in that case. The big problem here is that this code was not crashing, no error message, nothing, just working bad, but working.
I believe this has to do with the timing of your checking. During the pushViewController method, the next view controller's viewWillAppear: method (and others, such as the one you're checking) are in the process of getting called. I believe after all those method are called, the view controller is considered on the navigation stack AFTER the animation is done completing.

iPhone App - dismissing modal view controller doesn't dealloc it

I have a UIViewController (call it NumberTwo) which I presented as a modal view controller from another UIViewController (call it NumberOne). NumberTwo contains a touchesBegan method which listens for touches, and it also has an accelerometer method which listens for device orientation changes in the x, y, or z direction. NumberTwo has a button called "Done" which, when tapped, dismisses itself as a modal view controller:
[self dismissModalViewControllerAnimated:NO];
But it seems as though it's still listening for touches, and it's still listening for accelerations. How can I completely free up NumberTwo when I dismiss it? I tried adding a release call as follows:
[self dismissModalViewControllerAnimated:NO];
[self release];
but that caused a EXEC_BAD_ACCESS.
Did you release the controller after you presented it? E.g. in your method in NumberOneController that presents it, do you have something like:
NumberTwoController * controller = [NumberTwoController alloc] init];
// do stuff to config controller
[self presentModalViewController: controller];
[controller release];
Unless you want to hang on to NumberTwoController for re-use, this would be the usual pattern. The presentModalViewController method ensures that the controller is retained while it's in use. It should then get tidied up when, within NumberTwoController, you call [self dismissModalViewControllerAnimated: NO].
I had a very similar issue that plagued me for days. It turned out that my view controller class wasn't being deallocated when I dismissed it because that view controller had an active NSTimer that wasn't being invalidated (stopped). I was able to kill the timer in viewDidDisappear.
Make sure you are releasing everything you use when you finish with it; The dealloc method is only called when the UIViewController and all of its properties/objects are no longer in use. Never use [self release]; you need to release it from the view controller that created it after you are finished with it.

pushViewController only works with animated:YES

I have found a strange behaviour when trying to push a viewcontroller onto the stack. The following works fine:
[self.navigationController pushViewController:myViewController animated:YES];
but if I change it to animated:NO it no longer works, doesn't seem to push at all. I was performing this in a viewWillAppear but I have also tried it in viewDidAppear but with no luck.
Any ideas what could be causing this?
Thanks
The problem is most probably not the call itself, but the placement of the call. Try putting the same action on a UIButton and it should 100% work. I've noticed that putting view controller manipulation routines like presentModal... and pushViewController... don't sometimes work in the viewWill* viewDid* methods. Or try making the calls from those functions with a performSelector:withObject:afterDelay after a short delay and see if that works.
Edit: there are a couple of ways of doing what you want to do. You can directly modify the navigation stack of a navigation controller, so when you are in view N+1, you can replace view N on the stack (by building a new navigation stack array and setting it in to the navigation controller), then pop, and you'll get the effect of "popping back to a different view controller". You can also issue multiple pops and pushes from the view controller you want to leave, but you have to be careful:
// pop back 2 controllers on the stack to the setup screen
//
// locally store the navigation controller since
// self.navigationController will be nil once we are popped
//
UINavigationController *navController = self.navigationController;
// retain ourselves so that the controller will still exist once it's popped off
//
[[self retain] autorelease];
// Pop back 2 controllers to the setup screen
//
[navController popViewControllerAnimated:NO];
[navController popViewControllerAnimated:YES];

Strange crash on selecting a UITableView cell

I am getting an EXC_BAD_ADDRESS crash when selecting a table's cell which should push a new view on the navigation controller.
Here is the stack trace (the CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION_ is always there):
alt text http://dl.dropbox.com/u/71415/crash_threads.jpg
I strongly suspect the new code I have added to load the initial data the app needs in a separate thread, partly because the init and loadView of the new view controller are being called and return fine. I am doing a [NSThread detachNewThreadSelector:#selector(loadData) toTarget:self withObject:nil]; in applicationDidFinishLaunching and then load a view showing a progress indicator. loadData does a [self performSelectorOnMainThread:#selector(setupMainUI) withObject:nil waitUntilDone:NO]; when data is ready. The UI (table and all) is loaded fine, the fresh data shows up great; it's only when a new view has to be pushed that the crash happens. Switching views via tab controller works fine as well.
Ideas?
Thanks.
Update:
This is what I am doing to load the new view controller:
NSArray *arrayForSection = [filteredGobos objectAtIndex:indexPath.section];
Employee *selectedEmployee = [arrayForSection objectAtIndex:indexPath.row];
if (self.employeeVC == nil) {
EmployeeVC *emplVC = [[EmployeeVC alloc] initWithEmployee:selectedEmployee];
self.employeeVC = emplVC;
}
[self.navigationController pushViewController:employeeVC animated:YES];
You have overreleased an object. Your app is signaled when trying to release the autorelease pool. That means something in the pool already was released and dealloced before. Try Build&Analyse or NSZombies to find the problem.
I don't think it has to do with your threading, as want you mentioned there looks right to me.

release viewcontroller after presenting modally

I was watching CS193P Stanford course on Itunes, and in one of the lectures a demo was given and
There it was said you could present the viewcontroller modally and then release it. Roughly like this (I know this isn't perfect but I'm on my PC atm)
[self.view presentcontentmodally:myVC]
[myVC release];
However this seems to produce problems. If I put a NSLog(#"%d", [myVC retainCount]) between those two lines then it returns 2 implying it is ok to release. However when I dismiss the myVC the app crashes. Nothing in the NSlog and the debugger won't show where it stopped.
But I used malloc-history or something that some blog said would help. And found that it was the myVC.
So should I be releasing myVC?
(also when the modalVC has been dissmissed should the app's memory usuage go back to before the modalVC was presented?)
Yes, you should release your view controller after passing it to a modal navigation controller. Just make sure you are not passing in a previously retained view controller unless you plan to manage its release manually.
For example, follow the lifespan of _myViewController here:
MyViewController *_myViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
UINavigationController *_modalNavigationController = [[UINavigationController alloc] initWithRootViewController:_myViewController];
[_myViewController release], _myViewController = nil;
[[self navigationController] presentModalViewController:_modalNavigationController animated:YES];
[_modalNavigationController release], _modalNavigationController = nil;
The modal navigation controller will increment the retain count of _myViewController, essentially taking ownership of it.
Once the modal navigation controller is dismissed and you are back to your original navigation controller, the modal navigation controller will receive a release message and in turn release its root view controller (_myViewController).
The retain count of this view controller will hit zero and the memory is then reclaimed.
I have just checked through a couple of my apps, and I am releasing my modal view controllers after each presentation, without problems. Which makes me think that you don't yet understand the Cocoa memory management model. Here's a sample:
TweetController *tweetController = [[TweetController alloc] init];
tweetController.content = content;
tweetController.delegate = self;
[self presentModalViewController:tweetController animated:YES];
[tweetController release];
Note that this controller was created with alloc/init, and wasn't previously released or autoreleased.
In addition, please don't rely on retain count checking; a retain could be from a previous autoreleased, which will go away very soon causing the sort of error you have been seeing.