iPhone: Zombie object in modalview and delegate - iphone

I have a crash in my App that sometimes occurs, I tested with zombies enabled and this method it found as a ZOMBIE, this method usually works OK but in some conditions like lots of navigate back and forth at somepoint it crashes.
I retain the datepickerView in #property and release it in deaaloc.

Set the datePickerDelegate to nil in dealloc. If it has a retain property after the first instantiation the delegate will probably have a dead reference in it and will randomly cause creates and crashes when Zombies are enabled. The crash happens because retain properties release the previous value and if it is a dead reference crashes ensue -- randomly. Also best to set delegates to assign, not retain.
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the picker to run, stop recording, search for there ivar (datePickerView), drill down and you will be able to see where all retains, releases and autoreleases occurred.

I see no reason to keep the picker in memory after it has been popped from stack...
Instead of retaining the DatePickerController, remove "autorelease", and "release" just after presentSemiModalViewController, as per reednj post on SemiModelDatePicker
TDDatePickerController* datePickerView = [[TDDatePickerController alloc]
initWithNibName:#"TDDatePickerController"
bundle:nil];
datePickerView.delegate = self;
[self presentSemiModalViewController:datePickerView];
[datePickerView release];
Hopefully this will alleviate the problem. Otherwise, it could simply be a problem with the SemiModalDatePicker extension.

Related

retain count of a view controller not equal zero after a release message

I have a view controller initialized like this: HomeViewController *homeVC = [[HomeViewController alloc] initWithNibName:#"HomeViewController" bundle:nil];
Then I've placed this method after I finished working with this view controller: [homeVC release]; and right after it i've placed NSLog#("%d",[homeVC retainCount]); the console displays 15 as a retainCount number, however, I put double [homeVC release]; lines and the same NSLog statement, result = app crashes ...
two questions:
1) can anybody explain that ?
2) how can I make the retainCount to be equal Zero ?
Various parts of code internal to the iOS SDK can/will retain your view controller as well, particularly if you are pushing to it, presenting it modally, associating it with a tab control, or doing pretty much any other nontrivial thing with it. In short, you are not the only one making use of your view controller. And your crash happens simply because adding the second release causes the view controller to eventually be released one too many times.
Moreover, manually inspecting the retain count of an object is not generally recommended, specifically because of cases such as this where the actual value does not match the value a developer might expect.
By matching every alloc/init, retain, and copy with a call to release, and by not worrying about precisely when the retain count reaches exactly zero (if you really want to know when this happens, set a breakpoint in dealloc). You have to write code that does not leak or over-release objects, assume that the iOS SDK will do the same, and trust that your object will be released at the correct point in time. Alternately, switch to SDK version 5 and use automatic garbage collection instead.
Do not use retainCount. It is meaningless. Just follow the memory management rules, release when you're the owner, and you will be OK.

UINavigationController and UIViewController dealloc

I recently changed my app to use a UINavigationController, I was using a UINavigationBar before, with cascade subView adding, which was a bit tenuous.
I'm facing a problem of memory usage. Leaks tool doesn't show any leak, but ViewControllers I create and add to the UINavigationController never seem to be released. So memory usage grows everytime I create a new VC and then press the NavigationController's back button.
I simply create and add my VCs this way:
DetailViewController* detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
// setups
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
The app never goes through ViewController's dealloc and viewDidUnload methods. Shouldn't these be called everytime I press the back button?
I've searched many tutorials and read Apple's memory management, but there's nothing about VC's lifetime in memory when using NavigationController.
Maybe you are not doing something wrong and instead you are facing something like this
In the Blog post it was the question whether we have to manually release IBOutlets or not. As it turns out we should. This was reproduceable in iOS 3.1.3 but I didn't test it in iOS 4.0 yet.
The second aproach is to override your view controllers retain and release method and print out the retain count. I had a simimlar problem, that some view controllers dealloc method did not called so I override this methods to see wether someone has still a retain on it. As it turns out it did.
Edit:
When I printed my retain count, it would sometimes reach ~98 caused from the framework, so thats not really to worry.
If your last retain count stays at 2 and the dealloc method won't be called, than there is someone that has still a retain on it.
In this case you should search on other places.
For example another problem I encountered during this same problem:
Sometimes I would use
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateUI) userInfo:nil repeats:YES]
to constantly update the UI. But what I forgot was, that the NSTimer will retain the target object (which was the ViewController). Because the NSTimer retained your view controller your dealloc will never be called because someone (NSTimer) has still a retain on it. So you have to make sure to invalidate the NSTimer BEFORE dealloc method to properly release the view controller.
Edit2 in response for a comment below:
A retain declaired property does as follows (exsample):
- (void)setTarget:(id)value {
if (value != target) {
[target release];
target = [value retain];
}
So it does first release your current self.target then retains the new value. Since you are assigning nil your target will be nil afterwards. Further info about Properties can be found in the Apple doc.
I have seen this as well. As you pointed out, I haven't seen anything definitive in the docs, but my belief is that they are retained in memory until memory is needed. It makes sense from a performance perspective as doing so allows the app to quickly navigate between the different views.
Bottom line is, I wouldn't worry about it. You could fire off some Low Memory Warnings in the Simulator and see if it actually releases your VCs.

How can I tell if a referenced object has been deallocated in objective-c?

After upgrading to iPhone OS 4.0 the application started to crash after switching between applications. The application crashes in the same place when the application receives a memory warning.
It seems like some objects are automatically deallocated when a memory warning is received and then when we try to use the deallocated objects the application crashes.
Is it possible to test if an object has been deallocated, so that we can reallocate them?
You can't test whether a specific object has been deallocated because after deallocation, the object no longer exist. The only thing you can do is test whether a reference to the suspected object from another object is still non-nil.
Your problem here isn't deallocation per se but rather mismanaged retention. You have an object that has been marked as no longer being in use and the system is killing it as the system should. The only reason that you see it during low memory is that the system stops and drains all the release pool instantly instead of waiting for the normal cycle.
You need to make sure you have properly retained all the objects you need so they won't be improperly released. A retained object is not deallocated even in low-memory situations.
Edit
I would add that the most common cause of low-memory crashes is assuming that a view or a resource in a view is always present even when the view is not displayed. The system will purge undisplayed views and their resources (like images) in low-memory. Check the didReceiveMemoryWarning of the view controllers.
You can add
-(void)dealloc { ... }
And leave it empty if it's the right to do, and add breakpoint in it.
This answer correct to ARC and NON-ARC
Implement the method dealloc inside a UIViewController to see the moment it is being released from memory
- (void) dealloc
Print the reference of any object you want to test.
NSLog("Get pointer: %#", self); // ViewController
Then set a break point at a place where you want to test if the object is still existing. If you ran into the breakpoint, check the objects pointer in the debugger with
`po [pointer_printed_before]
Here you can see, the pointer is not available anymore, there is no object anymore after the dealloc method printed a log.

NSZombieEnabled hides EXC_BAD_ACCESS error entirely

So I have a subclass of a UIView that starts causing EXC_BAD_ACCESS errors when I go through a specific set of conditions (run on iPad instead of iPhone or simulator, first login only). It throws the exception when the UIView subclass gets autoreleased from the pool (i.e. the pool is releasing, not when I'm calling [view autorelease], during the last line, where I have [super dealloc]. I heard about using NSZombieEnabled, so I tossed that on to see if I could get any more information about it, but now it hides the error completely!
Does anyone know a bit more about this type of situation? I thought NSZombie would start spewing stuff into my console like before, but I'm hoping that the nonexistance of errors would tell me some sort of information as well.
- (void)dealloc
{
[loadingLabel release];
[indicatorView release];
[super dealloc];
}
Edit: Ok, so I sorta solved the underlying problem:
One of my properties was:
#property (nonatomic,retain) NSString * title;
However, the code for that property is as follows (loadingLabel is a UILabel):
- (void)setTitle:(NSString *)title
{
loadingLabel.text = title;
[loadingLabel sizeToFit];
[self setNeedsLayout];
}
- (NSString *)title
{
return loadingLabel.text;
}
I don't actually retain anything, but rather only do a UILabel.text, which is a copy property. So I changed my own title property to reflect this, and the error has disappeared.
However, I still don't really know how or why this error popped up in the first place, and why it only appears on the iPad platform (not the iphone, or even the ipad simulator).
So I have a subclass of a UIView that starts causing EXC_BAD_ACCESS errors when I go through a specific set of conditions (run on iPad instead of iPhone or simulator, first login only). It throws the exception when the UIView subclass gets autoreleased from the pool (i.e. the pool is releasing, not when I'm calling [view autorelease], during the last line, where I have [super dealloc]. I heard about using NSZombieEnabled, so I tossed that on to see if I could get any more information about it, but now it hides the error completely!
You get EXC_BAD_ACCESS because you tried to work with a dead object.
NSZombieEnabled makes objects not die. Since the object never died, your app didn't crash. Instead, you'll get a message in the Console log (the Debugger Console when running under Xcode), telling you what you did wrong and suggesting a breakpoint to set.
To be more specific, the NSZombie message will tell you what class of object you sent a message to, and what message you sent it. If you set the breakpoint and run your app with the debugger active, the debugger will interrupt (“break”) your app at that point, so that you can look around and see what sent the zombie object the message.
I don't actually retain anything, but rather only [assign to] a UILabel.text, which is a copy property.
Thus, the string presumably died off for not being owned by anything. With NSZombieEnabled and the above technique, you can confirm the theory that it was the string that was dying off prematurely.
A better and easier way, though, is to use Instruments's Zombies template. Instead of a message appearing in Xcode's Debugger Console, a flag in will appear Instruments's timeline with the information. That flag will have a go-to-iTunes-Store (➲) button you can click for more information about the problem.
Could you clarify - do you mean that you throw an EXC_BAD_ACCESS exception or you (on purpose) cause the system to throw an EXC_BAD_ACCESS exception? How do you do this? Please show some code. NSZombie will spew to the console if you try to call an instance method on it. Are you doing that?
NSZombie should produce output to the console in the same location a crash would have occurred.
Have you tried also running Instruments with the ObjectAlloc tool, and enabling both retain count and zombie detection in there (you need it both in the executable and configure the ObjectAlloc instrument, click on the "i" next to ObjectAlloc). When a message is sent to a zombie that instrument will flag you with a special popup saying a zombie was detected.
Remember the iPad SDK is still beta, maybe you should report this but to apple if you can confirm this to be a bug. Unfortunately their bugtracker is horrible from my experience.
The behavior of NSZombie is to never decrease an objects retain cound if release is called. However it keeps track of the would-be retain count and logs acess to the object after it would have been deleted on the console. It puts the Object adress alongside the error message, together with Instruments you can easily locate the Object at that adress and determine where it has been alocated and who retained/released it.

iPhone - insertSubview makes ObjectAlloc jump

Whenever I add a new viewController my ObjectAlloc jumps up really high and never comes back down. Even after calling removeFromSuperview. Is this normal?
if((UIButton *) sender == gameArcadeBtn) {
GameArcade *gameArcadeController = [[GameArcade alloc]
initWithNibName:#"GameArcade" bundle:nil];
self.gameArcade = gameArcadeController;
[gameArcadeController release];
[self.view insertSubview:gameArcadeController.view atIndex:1];
}
Instantiating a view always creates many objects.As long as this view is in memory or has not been autoreleased, the objects will remained alloced in memory. Thus, to answer your question, this is normal.
It sounds like you are worried about memory usage and while it is important to watch the object allocs so that it doesn't get too it is more important to find your app leaks.
Some memory management tips:
1) do lazy loading. Only load your views when the user asks for them, not all at the beginning of the app
2) remove everything that you possibly can when you dont need it anymore. This means doing tons of work in viewWillAppear and viewDidDisappear
3) learn about #properties and how it relates to autoreleasing, and do not use properties for everything.
4) As appealing as it is, avoid autorelease and manually release objects when you dont need them anymore.
that's probably due to the fact that you're still retaining the view's controller in the class. try releasing that