Have only one question "How to right dealloc object when app goes to background ?". I'm working on some app, everything works great and fine. When i put app to background and then start it again it's crashes. Not immediately(app stars right where i closed it) , but when i choose some of cells or just scroll tableview for example. So i'm pretty sure that app calls already released data.
here is example of dealloc
- (void)dealloc {
[anObject release];
[array release];
[locationManager release];
[currentLatitude release];
[currentLongitude release];
[filteredListContent release];
[super dealloc];
}
Any advises?
Unless you specifically deallocate things in your app delegate's applicationDidEnterBackground method, nothing should be deallocated for you automatically.
I have never experienced the problem you're having. Are you certain the same thing doesn't happen after a while even if you never put it in the background?
Here's a good explanation of how all of the backgrounding stuff fits together:
Understanding iOS 4 Backgrounding and Delegate Messaging
I review and re-write my own code. The problem was as i expected in deallocation of memory. I used autorelease where i shouldn't. It still weird cause app did crash when i open it again.
Thanks everyone, not you guys who gift to me 2 negs, you are jerks. Don't be offended,but instead of give some advise you just give ungrounded negs.
Never release any object like this. Use
- (void)dealloc {
if(anObject){
[anObject release];
anObject = nil;
}
if(array){
[array release];
array = nil;
}
//same approach for all.
[super dealloc];
}
Related
I'm trying to figure out why pushing a viewController in my tableView using didSelectRowAtIndexPath would cause a crash in iOS 4.3, but in iOS 5.0+, it works fine.
It crashes right when I call:
self.customViewController = [[[CustomViewController alloc] initWithNibName:#"CustomViewController"bundle:nil] autorelease];
anytime after the first time the customViewController has been pushed.
Here's my relevant code:
#property (nonatomic, retain) CustomViewController *customViewController;
-(void) dealloc // Dealloc of tableView.
{
[customViewController release];
customViewController = nil;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.customViewController = [[[CustomViewController alloc] initWithNibName:#"CustomViewController"bundle:nil] autorelease]; // Release old, allocate new, set it.
[[self navigationController] pushViewController:customViewController animated:YES];
[customViewController release]; // Balance out pushViewController's retain.
}
Thanks.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.customViewController = [[[CustomViewController alloc] initWithNibName:#"CustomViewController"bundle:nil] autorelease];
[[self navigationController] pushViewController:customViewController animated:YES];
[customViewController release]; // Balance out pushViewController's retain. ---->NO
}
The last release is an extra one that is not needed.
You already have done an autorelease on it to have it's retain count down by one.
We will analyse this line
self.customViewController = [[[CustomViewController alloc] initWithNibName:#"CustomViewController"bundle:nil] autorelease];
you create a CustomViewController retain count == 1.
You say autorelease on it so retain count will be 0 later (probably the end of the run loop), but for now it's still 1 that is why you still have access to it, but treat it as 0.
After that you say self.customViewController, that property is retain, so retain count == 1.
And you are taking care of that 1 in your dealloc.
As of your comment :
// Balance out pushViewController's retain.
You don't Balance those, you balance only the one YOU own. If the system make retain on your objects, it will release them when the system don't need them anymore.
Don't release the customViewController. You've already autoreleased it when you assigned it, so you've already given up ownership from the alloc. You don't have to release or autorelease the object again. The navigation controller takes ownership and will relinquish it by itself at the appropriate time.
Also, it's coincidence that you may see it in one version and not another. This is a memory management problem, so any corruption you might see (crashes, etc.) will be dependent on the state of memory on the device whenever you run the app. You may see a crash all the time, never, or only after running Skype but before opening the Photos app.
A good way to look for these is to enable zombies during your debugging sessions. With zombies enabled, objects are never actually released. Instead they are put into a zombie state and if they're ever sent a message again, they will abort the app and show you where the stray message was sent to help you debug your memory issues.
Hy
I've got a UIView. In one method, I alloc a WebView, and set it's to a retain property.
self->webView= [[UIWebView alloc] initWithFrame:self.frame];
Then I start to load a HTML string. After it's loaded, I resize the view and start a callBack to the superview to resize. It's working.
My problem is that, if the user go back before the view has been loaded, the view's are released. Then my WebView throw a BAD_ACCESS.
Here is the dealloc method:
-(void)dealloc{
[self.webView setDelegate:nil];
[self.webView stopLoading];
[self setWebView:nil];
[htmlStr release];
[super dealloc];}
The callback trace is shown in the screenshot. The interesting is that, if I don't release the WebView it is work's like the charm. If I release the WebView, then when it's deallocated, I get an error message in the log:
![bool _WebTryThreadLock(bool), 0x4e05150: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...][1]
EDIT: It has been fixed. It turns out, that my image loading method was guilty. I've start a new thread (NSOperationQueue and NSInvocationOperation in that) to load an image, and make a performSelectorOnMainThred: when it's finished. Whit that, I've loaded more than hundred small (1-2 KB) image, on every page switch, which was a really big overhead. When I wrote a method which download the images in one thread one by one, this bug has never came again
You are modifying UI from other tread than main. This is forbidden as UIKit is not thread-safe (hence the crash...). If you want to modify the UI from another thread, you must use:
performSelectorOnMainThread:withObject:waitUntilDone:
Other thing I've notice in your code is that you incorrectly release your properties in -dealloc. You should not use synthesized setters like this:
[self setWebView:nil]; // same as self.webView = nil;
You should not, because it can bring you lots of problems if you start using KVO (Key-Value Observing) on you properties... Instead just write:
[webView release];
or, if you want to avoid "The Heisenbug":
[webView release], webView = nil;
EDIT: you can also benefit from answer to this SO question: How to safely shut down a loading UIWebView in viewWillDisappear?
Dont call it with self.webView in dealloc, just use webView:
- (void)dealloc {
if ([webView isLoading])
[webView stopLoading];
[webView setDelegate:nil];
[webView release], webView = nil;
[super dealloc];
}
It has been fixed. It turns out, that my image loading method was guilty. I've start a new thread (NSOperationQueue and NSInvocationOperation in that) to load an image, and make a performSelectorOnMainThred: when it's finished.
Whit that, I've loaded more than hundred small (1-2 KB) image, on every page switch, which was a really big overhead. When I wrote a method which download the images in one thread one by one, this bug has never came again.
I do the following:
Path2D *pathToRemove = [path copy];
[[[self undoManager] prepareWithInvocationTarget:self] removePath:pathToRemove atIndex:index];
[pathToRemove autorelease];
I also have a clear button that does:
[undoManager removeAllActions];
Problem is that the removeAllActions crashes the app. When I removed the [pathToRemove autorelease], it worked (or at least didn't crash. It could still be a memory leak). I guess I was assuming that the undoManager retained 'pathToRemove' when passed in the 'prepareWithInvocationTarget' call.
Is that not the case? If that is not the case then the crash could happen because the call to 'removeAllActions' is releasing the 'PathToRemove' object. But that would mean it is a bug in NSUndoManager which is highly unlikely.
I can say that my copyWithZone implementation is not likely to be the culprit either since NSLog outputs for '[pathToRemove description]' and '[path description]' show different addresses as expected.
Any help would be appreciated. Thanks.
According to the documentation, the prepareWithInvocationTarget: method doesn't retain the arguments passed to it. From the NSUndoManager documentation, it appears that it simply captures the NSInvocation and later replays it. NSInvocationobjects don't retain the objects in their arguments unless specifically asked to do so.
That doesn't quite explain the crash, because removeAllActions is just supposed to clear the undo stack and not do anything to the objects.
Hope this helps some in tracking down the source of the crash.
In my experience, it's not a release/retain issue. You've to clear the stack after the Undo/Redo Operation. To do this you can register your viewController for the NSUndoManagerDidUndoChangeNotification notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(clearUndoRedoStack) name:NSUndoManagerDidUndoChangeNotification object:nil];
and then clear the stack onto the specified method:
- (void)clearUndoRedoStack {
[undoManager removeAllActions];
}
Maybe someone can help me with this strange thing:
If a user clicks on a button, a new UITableView is pushed to the navigation controller. This new view is doing some database querying which takes some time. Therefore I wanted to do the loading in background.
What works WITHOUT leaking memory (but freezes the screen until everything is done):
WorkController *tmp=[[WorkController alloc] initWithStyle:UITableViewStyleGrouped];
self.workController=tmp;
[tmp release];
[self.workController loadList]; // Does the DB Query
[self.workController pushViewController:self.workController animated:YES];
Now I tried to do this:
// Show Wait indicator
....
WorkController *tmp=[[WorkController alloc] initWithStyle:UITableViewStyleGrouped];
self.workController=tmp;
[tmp release];
[self performSelectorInBackground:#selector(getController) withObject:nil];
}
-(void) getController {
[self.workController loadList]; // Does the DB Query
[self.navigationController pushViewController:self.workController animated:YES];
}
This also works but is leaking memory and I don't know why !
Can you help ?
By the way - is it possible for an App to get into AppStore with a small memory leak ? Or will this be checked first of all ?
Thanks in advance !
No, small memory leaks will not (most likely) you application to be rejected from appstore.
In your example as you run your method in separate thread you should create and dispose NSAutoreleasePool object for that thread to handle autoreleased objects. Following changes to getController method should do the trick:
-(void) getController {
NSAutoreleasedPool *pool = [[NSAutoreleasedPool alloc] init];
[self.workController loadList]; // Does the DB Query
[self.navigationController pushViewController:self.workController animated:YES];
[pool release];
}
For more details see Autorelease Pools section in memory management guide. Relevant quote from there:
If you spawn a secondary thread, you
must create your own autorelease pool
as soon as the thread begins
executing; otherwise, you will leak
objects. (See “Autorelease Pools and
Threads” for details.)
Btw, you're calling pushViewController: from a background thread. This is bad.
You should only do things to the UI - like pushing view controllers and changing UI items - from the main thread. If you don't, things break.
See the Cocoa Fundamentals Guide section titled "Are the Cocoa Frameworks Thread Safe?": it says "All UIKit objects should be used on the main thread only."
uiimagepickerview controller creating memory leaks in iphone - why?
Try to implement ui image picker view controller in your application & debug it.
You will find memory leaks in your application.
Why ui image picker view controller creates memory leaks.
-(void)addPhotos:(id)sender
{
if(imagePickerController==nil){
imagePickerController=[[UIImagePickerController alloc]init];
imagePickerController.delegate=self;
imagePickerController.sourceType=UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePickerController.allowsImageEditing=YES;
imagePickerController.navigationBar.barStyle=UIBarStyleBlackOpaque;
}
[self.navigationController presentModalViewController:imagePickerController animated:YES];
}
dealloc of my view controller.
- (void)dealloc {
if(PhotoDateArray!=nil)[PhotoDateArray release];
if(imagePickerController!=nil) [imagePickerController release];
if(objDetail!=nil) [objDetail release];
if(Picimage!=nil) [Picimage release];
if(mySavePhotoController!=nil) [mySavePhotoController release];
if(LoadingAlert!=nil);
[super dealloc];
}
Video link explaining how I am getting the memory leak in it..
http://www.yourfilelink.com/get.php?fid=508534
Even though you have the nil check, it's still possible to leak memory. I think what is happening here is that you are calling alloc / init multiple times, but only releasing once. My guess it that addPhoto: is wired up to some button click, dealloc would only be called once when the delegate is trying to destroy. This creates a situation like this:
button click
alloc / init
button click
alloc / init (memory leak on first alloc'd picker)
close window
dealloc (free second alloc'd picker)
A better way might be the way Apple does it in the PhotoLocations and iPhoneCoreDataRecipes examples:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
Then listen for the didFinishPickingImage and imagePickerControllerDidCancel messages to your delegate and a call to [self dismissModalViewControllerAnimated:YES]; in both places should suffice.
I dont know about the rest of the code, but do you ever have a release?
[imagePickerController release]
UIImagePickerController loads and initializes PhotoLibrary.framework the first time it is shown. This memory won't be reclaimed until your application is closed.
(the code you posted doesn't appear to have leaks as-is, but that doesn't mean it won't interact with the rest of your application in a way that causes them)
I can explain this because I was having the same problem.
Don't test memory on the simulator!
If you test the apple code on a device the memory problem disappears.
I was having a memory alloc leak which I found in Instruments. All I was doing was opening and closing the image picker (open/cancel) and using Apple code, my code and other people's code, just like yours above.
All were showing the allocation going up and up each time, as if the picker was not being released. If you tried to release it, it would crash (over released).
Then I found a really helpful web page which basically stated:
"This doesn't happen when testing on the device"
So I switched from the simulator and ran the tests on the device. Lo & behold there was no allocation increase and it behaved normally.
This however is totally evil and now we can place no trust in the simulator to do a reliable job.
I want to add this to save people, the time, pain and bewilderment of wondering wtf is going on!