iPhone object checking to release - iphone

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.

Related

iOS correct way (memory management) for a method to return a value

If I have a class named Foo and I have this function + getIds that should return ids. Would the correct signature of + getIds look like this:
+ (NSArray *)getIds {
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
return ids;
}
What I'm wondering is that if I should use autorelease on *ids? There is no other way I assume? I can't do [ids release] after the return statement right?
You can send autorelease message along with alloc, init messages. You can also do, return [ids autorelease]; Note: You should not do both at the same time ;-)
You can not return [id release], because release method itself returns nothing.
The typically-correct memory management for returned objects is to have the called method set it as an autoreleased object, except when the method name contains "copy", "new" or "alloc". In those cases (copy/new/alloc), the returned object is retained, and the caller owns it (i.e. the caller is responsible for making sure they are released).
The code you wrote in the question will do the correct thing - it will return an autoreleased object.
When the caller gets the NSArray back, they can use the object as much as they like, and if they don't need the object in future calls, then they don't need to do any extra memory management. At the end of the run loop, the NSArray will be released, which is the desired behavior. If the caller does need the object to live longer, then they have to call retain on it (or something equivalent to that, such as calling something else that calls retain on it), and then they take the responsibility to call release on it later.
Useful stuff:
Apple's iOS memory management guide
My personal memory management guidelines (shorter, more biased)
Understanding run loops
Also, this will all go away when ARC (automatic reference counting, in iOS 5) becomes the norm.
You are already autoreleasing the array, so calling autorelease a second time would be an error that might result in a crash. The fact that you can't do a release after the return (you've left the function by then) is one of the reasons autorelease exists.
About whether the method should return an autoreleased as opposed to a retained object: Only methods that start with alloc or new or contain copy (as in mutableCopy) shall return retained objects. All other method shall return autoreleased objects.

Correct use of autorelease

I am trying to understand why my application crashes and I am going through my code. I am pretty sure that this is a valid use of autorelease:
(part of the code)
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSMutableArray *ids = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
return [NSArray arrayWithArray:ids];
}
Is this valid? The NSArray arrayWithArray returns an autorelease object doesn't it? I also have some difficulties in understanding the scope of autoreleased objects. Would the autoreleased object (if it is in this case) be retained by the pool through out the method that invoked the method that this code is a part of?
- (void)codeThatInvokesTheCodeAbove {
NSArray *array = [self.dao allQuestionsFromCategories];
...
}
Would the array returned be valid in the whole codeThatInvokesTheCodeAbove method without retaining it? And if it was, would it be valid even longer?
Got some issues understanding the scope of it, and when I should retain an autorelease object.
That is valid, but -- really -- you can just skip the [NSArray arrayWithArray:ids]; entirely as there is no need to create a new array.
An autoreleased object is valid until the autorelease pool is drained, which typically happens once per pass through a run loop (or "periodically, but never while your block is executing" when enqueuing stuff via GCD).
The documentation explains it all better than I.
There is no need to create an immutable array because the return will effectively "up cast" the NSMutableArray to NSArray. While this is meaningless at run time, it means that the caller cannot compile a call to a mutating method of the returned value without using a cast to avoid the warning. Casting to avoid warnings in this context is the epitome of evil and no competent developer would do that.
If it were an instance variable being returned then, yes, creating an immutable copy is critical to avoid subsequent mutations "escaping" unexpectedly.
Have you read the memory management documentation? Specifically, the part about autorelease pools? It makes it quite clear how autorelease works. I hate to paraphrase a definitive work.
[NSArray arrayWithArray:] returns an autoreleased object. If you want codeThatInvokesTheCodeAbove to take ownership of the array, you should call retain on it (and rename codeThatInvokesTheCodeAbove according to apple's guidelines). Otherwise, if you don't care that ownership of the object is ambiguous then your code is okay.
In other words, [NSArray arrayWithArray:] returns an array that you don't own, but you have access to it for at least this run cycle. Therefore, codeThatInvokesTheCodeAbove will have access to it for at least this run cycle. Ownership is not clear, since nobody called alloc, copy, new, or mutableCopy or retain. It is implied that NSArray called autorelease before returning the new array, thus relinquishing ownership.
My information comes from http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH.
So, to answer your question, yes your posted code is valid. Whether it's correct depends on what it is you are trying to accomplish.
Autoreleased object are objects that are marked as to be release later.
There is a very particular object that is automatically created by UIApplicationMain: an UIRunLoop.
Imagine it like a while structure, it cycle until application is terminate, it receives every event and properly resend it to your interested classes, for example. Just before UIApplicationMain there is a command to create an NSAutoreleasePool that, once the NSRunLoop is ready, attach to it. When you send an -autorelease command to an object, the NSAutoreleasePool will remember to release it when is released itself. It's dangerous to use it many times in platforms that has less memory (iOS devices), because objects aren't released when you send an -autorelease command but when the NSAutoreleasePool is drained (when app releases it).
If you want to free the non-mutable list before you return, you can use something like this:
- (NSArray *)allQuestionsFromCategories:(NSArray *)categories {
...
NSArray* result;
NSMutableArray *ids = [[NSMutableArray alloc] init]; // AUTORELEASE REMOVED FROM HERE
while (sqlite3_step(statement) == SQLITE_ROW) {
[ids addObject:[NSNumber numberWithInt:sqlite3_column_int(statement, 0)]];
}
result = [NSArray arrayWithArray:ids]; // COPY LIST BEFORE IT IS FREED.
[ids release]; // MUTABLE LIST FREES _NOW_
return result; // NONMUTABLE COPY IS RETURNED
}
It is not worth doing this unless your mutable array is likely to sometimes use a lot of memory.

Autoreleasing object returned from NSMutableArray

When a method returns an object that is taken from and NSMutableArray does the object must be autoreleased? Check the following method. Also should I autorelease the nil value?
-(NSObject*)getElementByID:(NSString*)ID{
for(int i=0;i<[elements count];i++){
NSObject *element = (NSObject*) [elements objectAtIndex:i];
if([element.key isEqualToString:ID]){
return [element autorelease];
}
}
return nil;
}
You must not autorelease element because you are not an owner of it (you have not put a retain on it). You would have become an owner of it if you acquired it using alloc, new or retain. Since you acquired this object calling objectAtIndex:, you do not own it. See Three Magic Words. Calling autorelease here will cause a crash later do to over-release.
Your method name is incorrect and breaks KVC. A method that begins with get must take a pointer that will be updated with the result. This should be elementForID:. As noted above with the three magic words, naming in ObjC is very important to writing stable code
As a side note, it is traditional to use id is most cases rather than NSObject*. They mean slightly different things, but typically id is correct.
You never need to do any memory management related things to nil. So, no, you should not send autorelease to nil.
You also should not need to send autorelease to the element object that you are returning from your elements array. That object you are returning will remain in memory by virtue of elements itself having retained it. If the calling method would like to retain the value that you return, it may. But if that calling method only uses the returned value within its own scope, it is safe for it to do so without retaining it.

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.

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