Is release without prior retain dangerous? - iphone

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

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.

iPhone object checking to release

I want to check if an object has some count or not Here is my testing code
NSMutableArray *array=[[NSMutableArray alloc]init];
if(array)
{
NSLog(#"hiiiiiii");
}
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
if(array)
{
NSLog(#"hiiiiiii");
}
Here in both cases i got same output as printed "hiiiiiii".
Can anyone tell me how will i check if my object need to release or already released.
I know that i should have track of my object's counters but i am at a stage where my code is too much complexed and i need help..
Please help..
ALso tell that how much memory leak is allowed by apple?
There is no way to check if you "should" release an object. Doing something like "if(object)" only checks the pointer to the object. It will return true even if the object it was pointing to was destroyed a long time ago. This is what happens in your second case. The object is destroyed when you call release, but the pointer is still pointing at something, so it returns true. It will only return false if the pointer is set to nil.
However, there is a simple set of rules for calling release. If you ever call "alloc", "new", "copy", "mutableCopy" or "retain" on object, you must always call "release" or "autorelease" on it. That will prevent any memory leaks.
Apple does not have a publicized amount of memory leaks allowed. It is always safest to eliminate any known memory leaks; plus, it will mean better performance for your customers.
In your second case you are releasing the NSMutableArray but still it store a non zero value although it's no longer for use (To call function OR fetch value).That the reason your if condition got true.
Just remember whenever you call release on any object, Do'nt forget to assign nil to that, So your second code should look like below.
CASE-2
NSMutableArray *array=[[NSMutableArray alloc]init];
[array release];
array = nil;
if(array)
{
NSLog(#"hiiiiiii");
}
There is a simple rule of memory management in Object-C if your alloced or retain any object you must call release on that,
Read memory management Guide from Apple.

Releasing an object but still able to use it

I had understood that once you release an object, you shouldn't use it as it will cause an error since it is not in memory anymore.
But reading thru this Apple guide, I found this code, and have also seen it before, but I would just move the [object release] to the end of my code, so as to avoid getting an error. But it seems that it is accepted and works. So, why does this work? How can it keep setting variables to dateAttribute after it's been released?
(Line 3 is the one in question):
NSMutableArray *runProperties = [NSMutableArray array];
NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];
[runProperties addObject:dateAttribute];
[dateAttribute release];
[dateAttribute setName:#"date"];
[dateAttribute setAttributeType:NSDateAttributeType];
[dateAttribute setOptional:NO];
Got it from here: Creating a managed object model in code
There are few points we should discuss.
release does not always make the object deallocated. The object will be deallocated only at the "last" release, i.e. when the retain count drop to zero.
Despite of that, it is still hold true that you should not use the object after you release it, because it is possible that it might be deallocated already.
The NSMutableArray will retain the object until it is removed from the array, or the array itself be allocated.
The example take the advantage that the array will retain the reference when added, so the reference will not be deallocated yet after releasing dateAttribute. However, this is not a good style because its validity depends solely on the nature of the class NSMutableArray itself, and it breaks common rule that we should not use released reference.
Technically, this is bad style, however it does work.
NSMutableArray (the runProperties addObject) calls retain on the dateAttribute. Therefore, calling release does not destroy the dateAttribute (there is still one reference).
For readability and refactoring reasons, I would also place the call to release last.

Objective-C memory model

I am attempting to wrap my head around one part of the Objective-C memory model (specifically on the iPhone, so no GC). My background is C/C++/Java, and I am having an issue with the following bit of code (also wondering if I am doing this in an "Objective-C way" or not):
- (NSSet *) retrieve
{
NSMutableSet *set;
set = [NSMutableSet new];
// would normally fill the set in here with some data
return ([set autorelease]);
}
- (void) test
{
NSSet *setA;
NSSet *setB;
setA = [self retrieve];
setB = [[self retrieve] retain];
[setA release];
[setB release];
}
start EDIT
Based on comments below, the updated retrieve method:
- (NSSet *) retrieve
{
NSMutableSet *set;
set = [[[NSMutableSet alloc] initWithCapacity:100] autorelease];
// would normally fill the set in here with some data
return (set);
}
end EDIT
The above code gives a warning for [setA release] "Incorrect decrement of the reference count of an object is not owned at this point by the caller".
I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end?
From what I have figured out by trial and error, setB is correct, and there is no memory leak, but I'd like to understand why that is the case (what is wrong with my understanding of "new", "autorelease", "retain", and "release").
I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end?
You're leaving out the autorelease. When -(void)test gets a set, its retain count is 0. You don't retain setA, so it already has a retain count of 0 when you try to release it, hence the error message.
The fundamental rule for memory management is quite simple: calls to alloc, new and copy* must be balanced by calls to release/autorelease. The former take ownership, the latter relinquish ownership.
The only tricky part is when dealing with shared objects, where you don't take ownership of an object, so it might be discarded in between the time you get a reference to it and when you use it. This has a simple solution: if in doubt, retain it.
You can make things even simpler by using properties in many situations.
Don't think in terms of absolute numbers. That can be very deceptive. Think of retains and releases as deltas if you must have a number — in this case, the autorelease has already balanced the new (a +1 delta and a -1 delta), so that method manages its memory correctly and the receiver doesn't need to do anything unless it wants to keep the object around longer.
Definitely read the memory management docs. It really is as simple as following the rules described there. It's a very simple contract of ownership where you claim ownership when you want an object to stick around and relinquish ownership when you don't care anymore. In the case above, you relinquish ownership in the retrieve method, so trying to relinquish ownership when you don't have it is obviously a bug.
As the profiler message hints, you should be thinking in terms of ownership. As noted in the memory management rules, whenever you have an object that you have created with +alloc, +new, -copy, or -mutableCopy, you own it and are responsible for releasing it eventually. (In fact, +new is just shorthand for [[MyClass alloc] init].)
-retain takes an object that you didn't initially own and makes you own it.
-release takes an object that you own and releases ownership of it.
-autorelease takes an object that you own and releases ownership of it, but also guarantees that the object will exist for at least a little bit longer.
Your -retrieve method does not transfer ownership of the object it returns. This is good—it follows the memory management rules (the method isn't +alloc, +new, -copy, or -mutableCopy). Therefore, using -release on it without using -retain is an error. It would be equally valid to not retain or release the result from -retrieve, as long as the object will have a temporary lifetime—your -autorelease guarantees temporary existence of the object.
http://www.macresearch.org/difference-between-alloc-init-and-new
You probably want
NSMutableSet *set = [[NSMutableSet alloc] initWithCapacity: someNumber];
or
NSMutableSet *set = [NSMutableSet setWithCapacity: someNumber];

Use autorelease before adding objects to a collection?

I have been looking through the questions asked on StackOverflow, but there are so many about memory management in Objective-C that I couldn't find the answer I was looking for.
The question is if it is ok (and recommnded) to call autorelease before adding a newly created object to a collection (like NSMutableArray)? Or should I release it explicitly after adding it. (I know NSMutableArray willl retain the object)
This illustrates my question:
Scenario A (autorelease):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
}
Scenario B (explicit release):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
}
I assume both are correct, but I am not sure, and I sure don't know what the preffered way is.
Can the Objective-C gurus shed some light on this?
IMHO, which way is 'right' is a matter of preference. I don't disagree with the responders who advocate not using autorelease, but my preference is to use autorelease unless there is an overwhelmingly compelling reason not to. I'll list my reasons and you can decide whether or not their appropriate to your style of programming.
As Chuck pointed out, there is a semi-urban legend that there's some kind of overhead to using autorelease pools. This could not be further from the truth, and this comes from countless hours spent using Shark.app to squeeze the last bit of performance out of code. Trying to optimize for this is deep in to "premature optimization" territory. If, and only if, Shark.app gives you hard data that this might be a problem should you even consider looking in to it.
As others pointed out, an autoreleased object is "released at some later point". This means they linger around, taking up memory, until that "later point" rolls around. For "most" cases, this is at the bottom of an event processing pass before the run loop sleeps until the next event (timer, user clicking something, etc).
Occasionally, though, you will need to get rid of those temporary objects sooner, rather than later. For example, you need to process a huge, multi-megabyte file, or tens of thousands of rows from a database. When this happens, you'll need to place a NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; at a well chosen point, followed by a [pool release]; at the bottom. This almost always happens in some kind of "loop batch processing", so it's usually at the start and bottom of some critical loop. Again, this should be evidence based, not hunch based. Instrument.app's ObjectAlloc is what you use to find these trouble spots.
The main reason why I prefer autorelease to release, though, is that it is much easier to write leak-free programs. In short, if you choose to go the release route, you need to guarantee that release is eventually sent to obj, under all circumstances. While this seems like it might be simple, it is actually surprisingly hard to do in practice. Take your example, for instance:
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
// Assume a few more lines of work....
[obj release];
Now imagine that for some reason, something, somewhere, subtly violates your assumption that array is mutable, maybe as the result of using some method to process the results, and the returned array containing the processed results was created as a NSArray. When you send addObject: to that immutable NSArray, an exception will be thrown, and you will never send obj its release message. Or maybe something goes wrong somewhere between when obj was allocd and the required call to release, like you check some condition and return() immediately by mistake because it slipped your mind that that call to release later on must take place.
You have just leaked an object. And probably signed yourself up to several days of trying to find out where and why it is your leaking it. From experience, you will spend many hours looking at that code above, convinced that it could not possibly be the source of the leak because you very clearly send obj a release. Then, after several days, you will experience what can only be described as a religious epiphany as you are enlightened to the cause of the problem.
Consider the autorelease case:
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
// Assume a few more lines of work....
Now, it no longer matters what happens because it's virtually impossible to leak obj accidentally, even under extremely unusual or exceptional corner cases.
Both are correct and will work as you're expecting them to.
I personally prefer to use the latter method, but only because I like to be explicit about when objects get released. By autoreleasing the object, all we're doing is saying "this object will get released at some arbitrary point in the future." That means you can put the autoreleased object into the array, destroy the array, and the object might (probably) still exist.
With the latter method, the object would get destroyed immediately with the array (providing that nothing else has come along and retained it in the meantime). If I'm in a memory-constrained environment (say, the iPhone) where I need to be careful about how much memory I'm using, I'll use the latter method just so I don't have so many objects lingering in an NSAutoreleasePool somewhere. If memory usage isn't a big concern for you (and it usually isn't for me, either), then either method is totally acceptable.
They are both correct but B may be preferred because it has no overhead at all. Autorelease causes the autorelease pool to take charge of the object. This has a very slight overhead which, of course, gets multiplied by the number of objects involved.
So with one object A and B are more or less the same but definitely don't use A in scenarios with lots of objects to add to the array.
In different situations autoreleasing may delay and accumulate the freeing of many objects at the end of the thread. This may be sub-optimal. Take care that anyway autoreleasing happens a lot without explicit intervention. For example many getters are implemented this way:
return [[myObject retain] autorelease];
so whenever you call the getter you add an object to the autorelease pool.
You can send the autorelease message at any point, because it isn't acted on until the application's message loop repeats (i.e. until all your methods have finished executing in response to user input).
http://macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=last&x-showcontent=text
You have alloc'ed the object, then it's your job to release it at some point. Both code snippets work merely the same, correct way, with the autorelease way being the potentionally slower counterpart.
Personally speaking, I prefer the autorelease way, since it's just easier to type and almost never is a bottleneck.
They're both OK. Some people will tell you to avoid autorelease because of "overhead" or some such thing, but the truth is, there is practically no overhead. Go ahead and benchmark it and try to find the "overhead." The only reason you'd avoid it is in a memory-starved situation like on the iPhone. On OS X, you have practically unlimited memory, so it isn't going to make much of a difference. Just use whichever is most convenient for you.
I prefer A (autoreleasing) for brevity and "safety", as johne calls it. It simplifies my code, and I've never run into problems with it.
That is, until today: I had a problem with autoreleasing a block before adding it to an array. See my stackoverflow question:
[myArray addObject:[[objcBlock copy] autorelease]] crashes on dealloc'ing the array (Update: Turns out the problem was elsewhere in my code, but still, there was a subtle difference in behavior with autorelease…)