presentModalViewController memory leak or EXC_BAD_ACCESS - iphone

-(void) addBookmarkTapped:(id)sender {
BookmarkAddViewController *bookmarkAddViewController =
[[BookmarkAddViewController alloc] initWithName:currTitle link:self.addressBar.text];
[self presentModalViewController:bookmarkAddViewController animated:YES];
[bookmarkAddViewController release];
}
code above cause 'EXC_BAD_ACCESS' when back to the main controller. Same error if I make bookmarkAddViewController 'autorelease'.
It will not crash if I remove the release, but it will cause memory leak?
[bookmarkAddViewController release];
I see many examples doing the same way, why it doesn't work in my case?

It might have to do with your init method in bookmarkAddViewController.(Please post.) Make sure you dismiss the controller properly with [self dismissModalViewControllerAnimated:YES];.

Related

Releasing a UIView

NB: To clarify what I'm trying to do here:
I have an instance of a subclass of UIView. When this instance gets released from a View Controller I would like that the dealloc method of that instance be called.
The point being to release other objects within that instance of the subclass of UIView.
In the View Controller:
- (void)viewDidLoad
{
[super viewDidLoad];
self.mav = [[MapAreaView alloc]init];
[self.view addSubview:self.mav];
[self.mav release];
t_ = [NSTimer scheduledTimerWithTimeInterval: 20.0f target: self selector:#selector(onTick) userInfo: nil repeats:NO];
}
and:
- (void)onTick
{
NSLog(#"Releasing...");
[t_ invalidate];
t_ = nil;
[self.mav release];
[self.mav release];
[self.mav release];
NSLog(#"Done releasing.");
}
In MapAreaView:
- (void)dealloc
{
NSLog(#"map view area dealloc called.");
[super dealloc];
}
I am trying to release the MapAreaView and have it's dealloc method called.
Also, when I run this app, Releasing... and Done releasing. get printed, but not map view area dealloc called. And despite all of my excessive release messages sent to self.mav the app doesn't crash. Weird.
Ideas?
EDIT 1
#interface MemoryManagmentViewController : UIViewController {
MapAreaView *mav_;
NSTimer *t_;
}
#property (nonatomic, retain) MapAreaView *mav;
which is then synthesized: #synthesize mav = mav_;
EDIT 2
Please not that the timer is not for use in my real application. I'm just using it to learn about memory management.
First off, don't use [self.mav release]. This is incorrect use of properties, and is not guaranteed to release your object. Use self.mav = nil instead.
Secondly, I presume your crazy timer is there just to try and force the release of your view and isn't really code you are using? Because it really shouldn't be there!
To manage the memory of a view that you want to both keep a pointer to and add as a subview to your main view, remove the release and timer messages from your viewDidLoad. You now have one retained pointer to mav, via your property, and the view will be retaining it as well since it is a subview.
In viewDidUnload, your view no longer exists so it will no longer have a pointer to mav. Therefore, if you put self.mav = nil there, mav will be released.
You shouldnt try to release it while it is still a subview of another view.
You don't get to choose when dealloc gets run*
You don't know what else in the iOS framework is retaining your map view.
You should think about memory management in terms of ownership - while you want an object, make sure you've retained it (either explicitly or as a property) and when you are finished with it, make sure you release it (etiher by calling release, autorelease or by setting your property to nil).
Your map view will get released eventually, don't try to force it!
(And it's been said in many other answers but it pretty important so here it is again - don't call self.property release, do self.property = nil; instead :)
*not entirely true for object in libraries you have written yourself but it's definitely true for objects from third party frameworks, including ones from Apple!
The line:
[self.view addSubview:self.mav];
will retain self.mav and should be paired by this line in onTick.
[self.mav removeFromSuperview];
I'm not sure why your over-releasing in onTick doesn't release self.mav anyway - but if you do weird stuff you can guarantee that weird stuff will happen.
Don't release it within onTick again. Do these two steps:
[self.mavview removeFromSuperView];
self.mavview = nil;
That's it. There won't be any more references, so it will be deallocated.
First and foremost thing is
NEVER call release on self.iVar
Donot user self.iVar while allocating.
These are the basic things in memory management.

EXC_BAD_ACCESS and Zombies, Yet not really sure why it keeps coming up

I don't know what's going wrong here. The crash happens when switching back and forth between views.
Here's what instruments gives me:
Clicking into it references this code with the first action :
-(IBAction)pushnews; {
NewsViewController *news = [[[NewsViewController alloc]init]autorelease];
news.title =#"Page";
[self.navigationController pushViewController:news animated:YES]; }
I use autorelease sometimes but usually I just release it my self. Should I get rid of autorelease and add [news retain]
What am I doing wrong?
Edit based on answers:
Following EmptyStack's Advice: ViewWillDisappear Code looks like this:
- (void)viewWillDisappear:(BOOL)animated {
webView.delegate = nil; }
This seems to resolve issues (pending more testing)
In viewdidload I said: webView.delegate = self;, which may have been the issue!
My guess is that, there is a UIWebView in NewsViewController, and it is causing the crash. It is possible that, a delegate method of web view is called after the web view is released. If so, try to setwebView.delegate = nil; in NewsViewController's viewWillDisappear: method.
try this instead :
-(IBAction)viewcontroller;
{
NewsViewController *news = [[NewsViewController alloc]init];
news.title =#"Page";
[self.navigationController pushViewController:news animated:YES];
[news release];
}

Help Troubleshooting NSZombie Error Message

I have a modal view controller which is crashing when it dismisses itself. The error is EXC_BAD_ACCESS (yipee). I am tryin got use NSZombie to work out the problem. I get am getting the following :
2010-10-20 17:15:58.936 [24058:207] AddRunningClient starting device on non-zero client count
2010-10-20 17:16:06.846 [24058:207] * -[ViewController retain]: message sent to deallocated instance 0x6c2d4a0
What does this mean - does it mean that a message was sent to the Viewcontroller or that a message was sent to an object in the Viewcontroller ?
I am really stuck as the thread seems to be main :(
Thanks all in advance for any help,
Martin
EDIT
Thanks all for the quick replies. Here is how I am presenting the view controller :
-(IBAction)letsstartGame {
ViewController * sl = [[ViewController alloc] initWithNibName:#"ViewController" bundle:[NSBundle mainBundle]];
self.viewLink = sl;
[sl release];
[mainMenu stop];
[mainMenu setCurrentTime:0.0];
[self presentModalViewController:viewLink animated:NO];
[viewLink release];
self.viewLink = nil;
}
And dismiss like this :
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (waitingOver) {
[backgroundMain stop];
[fireworks stop];
[self dismissModalViewControllerAnimated:NO];
}
}
That means that you had an instance of an object of type ViewController, it was deallocated, and then you tried to retain it.
edit
You're over-releasing the object. Here's what you're doing:
ViewController * sl = [[ViewController alloc] initWithNibName:#"ViewController" bundle:[NSBundle mainBundle]]; //allocated, has a +1 retain count
self.viewLink = sl; //assuming a retain property, has a +2 retain count
[sl release]; //releasing, now has +1 retain count
....
[viewLink release]; //releasing, now has a 0 retain count
self.viewLink = nil; //attempting to release stale pointer, will result in a crash (perhaps not immediately, but eventually)
Get rid of the [viewLink release] line. It is wrong to have that in there.
It means you are sending a message to a deallocated instance.
So somewhere in your code you have failed to retain an object (probably ViewController) or have released it prematurely.
If you can post your code where you create the View Controller that might be helpful for us to debug.
The message is basically saying that you are trying to send a message (call a function) on/to an object that has already been dealloc'd (released and the memory freed). If you could send more code, I could perhaps attempt to determine why.

iPhone: Calling dealloc on parentViewController causes an exception

I'm dealing with viewDidUnload and dealloc methods and I've founded a problem when calling [super dealloc]; in parent view controller.
I have a lot of view controllers with custom code which I have putted outside on a parent view controller. So, when defining my view controllers I set a reference to the super class:
#interface LoginViewController : AbstractViewController
Then, at the dealloc method I call the AbstractViewController dealloc method:
//(Login View Controller code)
- (void)dealloc {
[user release];
[passwd release];
[super dealloc];
}
[super dealloc] execute the following code:
//(Abstract View Controller code)
- (void)dealloc {
[dbUtils release];
[loadingView release];
[super dealloc];
}
If I simulate a memory warning on iPhone Simulator, the following exception is thrown:
2010-03-03 11:27:45.805 MyApp[71563:40b] Received simulated memory warning.
2010-03-03 11:27:45.808 MyApp[71563:40b] *** -[LoginViewController isViewLoaded]: message sent to deallocated instance 0x13b51b0
kill
quit
However, if I comment the [super dealloc] line in AbstractViewController the exception is not thrown and my app still running.
Thank you for your help once again!
It looks like you're freeing your view controller but then trying to use it again. When you free your view controller because of the memory warning, remember to set the pointer to nil so you don't accidentally use it again. i.e. something like
[myLoginViewController release]; //!< Triggers the dealloc call
myLoginController = nil; //!< Makes sure we never use it again
or, if myLoginViewController is a property you can do this in a neater way :
self.myLoginViewController = nil;
Hope that helps,
Sam
Notice -didReceiveMemoryWarning does not trigger -dealloc, it triggers -viewDidUnload. So I guess it is your implementation of -viewDidUnload that does something wrong that causes the controller's final retention to be released so -dealloc is called. I've just encountered this problem in my code which is caused by a retain recycle that is released in -viewDidUnload.
This happened to me and took a while to figure out. One of the delegates was trying to send a message because the delegate was self and it was a strong reference. when I made it weak it seems to have fixed it.

presentModalViewController in viewDidLoad on first launch

I've been searching around but unfortunately have had no luck.
My app requires the user to sign in/sign up the first time he or she launches the app. I know how to determine first launch (using NSUserDefaults) but whenever I try to present the modal containing the sign in/ sign up controls, nothing happens.
Here's what I have:
-(void)viewDidLoad {
[self showLogin];
[super viewDidLoad];
}
-(void)showLogin {
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"AccountView" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:controller animated:YES];
[controller release];
}
However, nothing happens. The main view just loads as normal. Any help is greatly appreciated.
-Giles
[UPDATE]
Fixed simply by using..
-(void)viewDidAppear:(BOOL)animated
{
}
instead of
-(void)viewDidLoad
{
}
Thanks anyway!
/idiocy
I had the same issue and ended up using viewDidAppear as well. The only problem with the viewDidAppear approach is that if you load other UIViewControllers on top, then reshow the base, then your setup code gets called over and over. I ended up having to add a boolean value (initialised to YES) to this view controller and check that value before deciding what to do. Hope this helps someone...
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:(BOOL)animated];
if(justLaunched)
{
justLaunched = NO;
if(settingsFileExists)
{
[self displayMainView];
}
else
{
[self displaySetupView];
}
}
}
How about using performSelector:withObject:afterDelay in the viewDidLoad function? That's how I do it, with a short delay of 0.1s.
And invoking this in the viewDidLoad isn't very safe : the sequence viewDidLoad / viewDidUnload can occur at runtime when the iPhone needs to release some views in order to get back some free memory.
The side effect of such sequence would be that your login controller would be shown...
As you said the viewDidAppear looks better but not simply put it at the end of the appDidFinishedLaunching the delegate of your UIApplication?