How many times do I release an allocated or retained object? - iphone

I am making an iPhone game. I want to release all objects that have been allocated or retained. In the dealloc function I am releasing all such objects, but then I realized that sometimes I end up releasing objects when they have not been allocated yet. So I figured I need to check if its retainCount is greater than zero or not before I release it.
My question is:
Do I just check if the retainCount is greater than zero and then release it?
if([bg retainCount]!=0)
{
[bg release];
}
or
Should I release it as many times as its retainCount
while([bg retainCount]!=0)
{
[bg release];
}
Thanks for your help!

Do not use -retainCount.
The absolute retain count of an object is meaningless.
You should call release exactly same number of times that you caused the object to be retained. No less (unless you like leaks) and, certainly, no more (unless you like crashes).
See the Memory Management Guidelines for full details.

Autorelease makes retainCount meaningless. Keep track of retains & whether you own an object. Study & remember these rules: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH

Related

How to find the reference count of an object

I want to know the reference count of an object in my program. Can I?
Sure:
int referenceCount = rand();
The real answer, of course, is the retainCount method; NSUInteger rC = [someObject retainCount];. However, the value returned by it is useless.
never never use the retain count in a conditional
the retain count can never be zero
the retain count never reflects whether or not the object is autoreleased
a retain count of 2-bazillion is perfectly reasonable for some classes some of the time
the retain count for any object that passes through system API may be a seemingly random value within indicating a problem
Bottom line: If you treat the retain count as an absolute value, you are doing it wrong. You either increase or decrease the retain count through your code, Keep your plusses and minuses in balance, and you are doing it right.
You can, but you are wrong: you don't want to do that.
Isn't it meant to be...
[obj retainCount];
Never use retainCount, it does not work the way you think it does.
See: SO on finding retains/releases
As everybody said, you can, BUT DON'T USE IT.
Back when I started I also thought that using the ref count I could find my memory problems easier. I wasted TOO MUCH time. The number you get is simply wrong in the sense that you can not (easily) just use it to find your memory management issues.
It is by far better to really check all the manually created objects with alloc, new, and your manual retains.
Simply sit back and focus onthe question "Who has ownership of this variable?" All thouse will keep your var alive. Also be sure to set your ivars with self.ivar, otherwise the ownership to the object will not be set.
But the easiest is to just use ARC in the newest version. This takes care of (most) of all these questions....
Not sure why all the posts about not using retainCount, its been valuable in tracking down memory issues for me, now I wouldn't use it as a conditional, nor even understand how that would even be used, but you can add a simple category and use retain count adequately to determine lifetime usage of any given class.
#implementation replaceWithYourClassName (MemoryInspecting)
- (id) retain
{
NSLog(#"RETAIN: self [%#] : retain count [%d]", [self description], [self retainCount]);
return [super retain];
}
- (void) release
{
NSLog(#"RELEASE: self [%#] : retain count [%d]", [self description], [self retainCount]);
[super release];
}
And throw some breakpoints in there to track the context if that helps, as it often does.

Why is the retainCount still 1 after [object release]?

NSLog(#"first:%u",[object retainCount]);
[object release];
NSLog(#"second:%u",[object retainCount]);
Output:
first:1
second:1
Why doesn't the object get released?
a Quote from NSObject reference on retainCount method
This method is typically of no value
in debugging memory management issues.
Because any number of framework
objects may have retained an object in
order to hold references to it, while
at the same time autorelease pools may
be holding any number of deferred
releases on an object, it is very
unlikely that you can get useful
information from this method.
Object can be released but not when you think it will be. Basically, don't look at retainCount. It may not change until the next runloop or at all, it's an implementation detail. You will get a sense for when you need to release and when you don't with experience but until then rely on the clang analyzer.
First, retainCount doesn't give you a number you can use. It's meaningless.
Second, the reason the retainCount is 0 is probably that you try to work with an object that doesn't exist anymore. You're lucky your application doesn't crash, because your accessing invalid memory. Decreasing the retainCount just before deallocating an object is unnecessary, therefore Apple doesn't do it, probably.
Divide any number by zero and you will find the meaning of "object with retain count of zero".
I agree with the other comments about not using retainCount to get a reliable count.
EDIT: Ignore my stupidity below... :)
However, I've observed that setting the corresponding property to nil...
self.object = nil;
the retainCount does tend to be decremented immediately.

iPhone - What happens if retain after autorelease?

Do you know what happens if I retain an autoreleased object ?
Will it be released or does the retain wins ?
Do you know what happens if I retain
an autoreleased object ? Will it be
released or does the retain wins ?
The retain "wins" but thinking of it that way is full of fail.
retain and release are merely mechanisms via which you increase or decrease the retain count of an object. Autorelease is simply a delayed release; no more, no less.
If you retain an autoreleased object you are increasing the retain count NOW while the retain count will be decreased LATER. This happens all the time; [NSString stringWithFormat: #"...."] returns an autoreleased string that you retain if you want it to stick around beyond [most typically] the current pass through the event loop.
If you want to keep your variable around, you need to retain it. For example:
myButton = [[UIButton buttonWithType:...] retain];
The buttonWithType: method returns a UIButton that's been instantiated with autorelease. It'll take care of releasing itself (so to speak) when needed.
The retain will win out. This is very common, and is an excepted practice.
Usually convenience methods return autoreleased objects like
[NSString stringWithFormat:#""];
It is expected that you retain whatever objects you need to, so long as you remember to release them later.
Remember that autoreleases will happen at the end of the current system message.
From the article below:
"an autorelease pool is created for each message that is processed by the system and the objects in the pool are all automatically released after processing on that message has completed."
Some great explanations of this can be found here:
http://www.iphonedevsdk.com/forum/iphone-sdk-tutorials/7295-getters-setters-properties-newbie.html

NSArray release crashes with EXC_BAD_ACCESS

Another puzzler. I have an NSArray (iTours) containing 3 Objects and a retain count of 1.
This Array is released in the object dealloc method as follows:
- (void)dealloc {
NSLog(#"retain count für iTouren: %d", [iTours retainCount]);
[iTours release]; // triggers EXC_BAD_ACCESS
[super dealloc];
}
The console window shows the following message (no further details):
Program received signal:
“EXC_BAD_ACCESS”.
any clues what's going on? What did I miss?
Most likely, you are over-releasing iTouren and, thus, that call to release is causing the crash. That is, iTouren is already deallocated by the time you release the containing array and when that containing array sends release to the already deallocated iTouren your app crashes.
(Of course, iTours might be the object that is already deallocated. In any case, it is an over-release problem.)
Turn on zombie detection and see if that barfs up the specific problem.
Note that the number returned by retainCount is useless. Absolute retain counts are an implementation detail and will often be a specific value that seems like nonsense.
In this case, the final release of an object does not decrement the retain count. Why? Because that'd be a wasted cycle when the object is about to be deallocated anyway. It would be impossible for retainCount to return 0 because, by definition, an object with a retain count of 0 has already been deallocated and, thus, is no longer a viable message receiver anyway.
Never, ever, ever, rely on the retainCount method.
Ever.
Did I mention ever?
One is iTours the other one iTouren. You are logging a different object than that being released.
Assuming iTours and iTouren are different objects (namely that iTours is an NSArray containing iTouren), you've over-released iTours; maybe you had a failure in a setter and iTours was released without being reassigned and retained.
Be sure that your array does not contains itself. Releasing an array also release every object in it. Of course, if this is the case, the array should have a release count of two before you release it because arrays retain their elements.
A released and deallocated object will have a retain count of 1. A non-released object about to be released and deallocated will also have a retain count of 1. (Assuming memory is ever allocated for the object, some strings and numbers are never allocated, implementation detail that changes per Mac OS X release)
When an object is deallocated in current versions of Mac OS X, the memory is marked as free, nothing about the object is modified (unless you tell it to be). Thus, the retain count remains identical to the retain count before it was released.
This is the make a mistake and DIAF approach that help makes Mac OS X so solid.

Is release without prior retain dangerous?

I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html