Cocoa Touch Question. Should [NSMutableArray array] be retained? - objective-c

Here is the gist of some code I'm writing. I'm concerned that I am not properly addressing the retain/release issues with the array class method on NSMutableArray. Is the following actually leaking memory?
for(a while) {
// do stuff
NSMutableArray *a = nil;
// do stuff
if (!a) {
a = [NSMutableArray array];
}
} // for(a while)

You wouldn't leak memory in this code, and releasing the array yourself will cause a crash when the array is autoreleased at the end of the run loop.
Most Cocoa classes provide a couple of ways of making a new object, and are very consistent with this convention:
[[NSSomeObject alloc] init] : you are responsible for releasing the object (instance method).
[NSSomeObject someObject] : the object will be autoreleased for you, usually at the end of the run loop (class method). It's roughly equivalent to [[[NSSomeObject alloc] init] autorelease].
The proper use of the instance method would be:
a = [[NSMutableArray alloc] init];
// do stuff
[a release];
The proper use of the class method would be:
a = [NSMutableArray array];
// do stuff, array is in the autorelease pool
Note that Apple has recommended you stay away from the convenience methods as much as possible to improve performance. This is controversial advice, may not save much processor time, and separates the alloc-init from the release on an object you may not actually care much about keeping.

From the Cocoa Memory Managment Rules:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
Therefore with the line:
a = [NSMutableArray array];
you do not take ownership of the array, and it will be passed to you autoreleased. The memory will be handled for you automatically by the autorelease pool, and once it is no longer being used, it will be released for you. If you want to keep the array outside the current event, however, you must retain it, otherwise it will be released for you.

Yes, if you want it to stick around.
The returned object is an autoreleased object which will get deallocated when its autorelease pool gets purged.
All the array class methods that begin with "array" return these types of autoreleased objects.
Read this doc by Apple.

That's valid. It may help to just manage things manually when you have questions, to learn.
There is a convention:
init prefixes (init, initWithString:) indicate a retain count of 1, where
objectname prefixes (string, stringWithString:) indicates an autoreleased object
I have had the habit, for years, to release what I can at the call site, rather than pushing it to be autoreleased. Some autorelease issues then become painfully difficult to track down. Sure, autorelease is a convenience to the programmer in this case (provided nothing goes wrong), but adversely affects reuse, clarity, and performance (moreso in large codebases/programs).

Related

Cocoa example - Why there is NO need to retain or release messages

I'm new to Objective-C and cocoa. In the guide provided by Apple for Cocoa, there is a confusing example in memory management:
Suppose you want to implement a method to reset the counter. You have a couple of choices. The first implementation creates the NSNumber instance with alloc, so you balance that with a release.
- (void)reset {
NSNumber *zero = [[NSNumber alloc] initWithInteger:0];
[self setCount:zero];
[zero release];
}
The second uses a convenience constructor to create a new NSNumber object. There is therefore no need for retain or release messages
- (void)reset {
NSNumber *zero = [NSNumber numberWithInteger:0];
[self setCount:zero];
}
I am not sure why the object is created with 'new' instead of 'alloc & init' does not need to be retained/released. My understanding is that both are doing the same thing, except that with 'alloc & init' we can use custom checks and initialisation.
Many thanks.
The second example returns an auto released object. The code for the convenience constructor probably looks like this, at least when it comes to replicate the functionality.
+ (NSNumber *)numberWithInteger:(NSInteger)integer
{
NSNumber *number = [[NSNumber alloc] initWithInteger:integer];
return [number autorelease];
}
Autorelease is a way to defer sending a release method to an object while not delegating ownership of the object to the caller of the constructor. This is an important concept, because the naming conventions require you to not return ownership of an object unless your method starts with copy new alloc or retain. However, since you can't return an owned object, you would have to call release on it in your convenience constructor, which would then lead to you returning a deallocated object. So, autorelease allows you to return an un-owned object to the caller which will receive an actual release method later (when the current autorelease pool gets drained).
Autorelease methods are collected in so called autorelease pools, which are thread local quasi linked lists (they are not implemented as linked lists, but they do work like they were) and that just collect autoreleased objects. Objects can be added to them multiple times by calling, once for each autorelease method they receive. When the pools is drained or destroyed, all objects it contains will receive a release message. By default, the system will provide you with an auto release pool, at least on the main thread, but you can create your own ones using this code (which is also used in every main method, if you take a look):
#autoreleaspool
{
[foo autorelease]; // foo will receive a `release` method at the closing brace
}
By convention, all methods who's name start with "alloc" or "copy" or "new" increase the retain count by 1.
All other methods do not change the retain count. Since "numberWithInteger" doesn't start with "alloc" or "copy" or "new" it returns an object with a retain count of 0. But instead of setting it to 0 immediately (which would never work), it sets the retain count to 1 and then schedules it to be dropped down to 0 at some point in the future (usually when the event loop is idle, but you can manually make it happen sooner), using an "autorelease pool".
The only exception to the alloc/copy/new naming convention is, of course, the actual "retain" and "release" and "autorelease" methods, which increase/decrease the retain count or schedule it to be decreased later.
It is not a language feature, it's just a coding practice. Every method starting with "alloc" and "copy" and "new" sets retain to 1, everything else sets it to 1 but schedules it to be dropped to 0 later.
Of course, if you are using ARC, and you should absolutely be using ARC, then you don't have to worry about any of this because the compiler will find the last line of code that uses the object, and will insert a line of code after it to free up the memory. This leads to faster code, because the autorelease mechanism is a bit slow and sometimes uses too much RAM.
When ARC is enabled, none of those rules apply. The compiler ignores all your memory management code (or tells you to delete it), and writes it's own code. It's not actual garbage collection, it's just manual memory management that is generated by Xcode instead of written by hand.
Objects that are created with +alloc -init are returned with a retain count of +1, meaning that you have to call -release when you are done with this object. This is the same with +new , which is just a simple combination of [[ alloc] init], eg.
NSDate *date = [NSDate new]; // I will have to send -release at some point
As a convention, methods that contains init, new, create and copy will transfer ownership to you, meaning that you need to send -release at some point. Other methods will not transfer ownership, meaning that the object is autoreleased, ie. it has a short lifetime and is scheduled to be dealloced in the future. If you want this object to stick around, you will need to explicitly take ownership by sending -retain.
NSDate *date = [NSDate date]; // I won't have to send -release
// But this object will be dealloced soon
// so if I want it to stick around, I will need to retain it
This convention is not enforced by the language.
It is also useful to remember that this convention expands beyond the Objective-C part of the SDK, it is also the case in CoreGraphics and all C frameworks provided by Apple, and most third-party frameworks make use of this convention.
CGContextRef context = UIGraphicsGetCurrentContext(); // I won't have to release this context
CGImageRef result = CGBitmapContextCreateImage(context); // I will have to release this image
/* ... */
CGRelease(result);
As for your example : -numberWithInteger: does not contain either init, new, create or copy. So you don't need to -release it when done.

Releasing objects created by functions

I'm learning obj-c and I have a question about memory management:
Say I have a function that returns an NSDictionary, "fDictionary",
NSDictionary *fDictionary {
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:1], #"blah",nil];
return dict
}
that is called by a particular method:
-(int)fNumber {
NSDictionary *f = fDictionary();
return [[f objectForKey:#"blah"] intValue];
}
What I'm unclear about is how/where I should be releasing the NSDictionary object.
Should I release it in the method, or autorelease it in the function?
If the function was written properly, the dictionary is autoreleased, so you don't have to release it at all. It will be released soon, by the autorelease pool.
You only release what you yourself retain or copy. These are the things you "own". Be sure not to release them too early. The usual point is before the end of the function they are allocated or retained in, if they are local. If they are ivars, the best point is, usually, the dealloc of the class to which the ivar belongs.
Without knowing anything about fDictionary it's difficult to be sure, but the convention followed in most Object C code is as follows:
You own it if the instance was created with an alloc or copy
You own it if you retain it
Otherwise you don't own it
If you don't own it you should not release it.
So by convention, the function would return an autoreleased object and you wouldn't need any extra management in your method.
The general rule is if your code alloc's something, you need to release or auto-release it.
If this was someone else's function, you would expect that the returned dictionary was autoreleased - which is the convention here. I would ensure that fDictionary returns an autoreleased NSDictionary.
If you have received an object from a method which name begins with “alloc”, “new”, “copy”, or “mutableCopy”, you have to release or auto-release it. Otherwise it is already autoreleased.
If you have retained something, you have to release it, nothing else will do that for you.
Every Obj-C programmer must read Memory Management Guide.
No.
NSDictionary dictionaryWithObjectsAndKeys: (which is really just [[[NSDictonary alloc]initWithObjectsAndKeys:, nil]autorelease]) returns an autoreleased NSDictionary. This means the dictionary will automatically be released when the computer decides it is no longer needed.
If in fDictionary() the dictionary was alloced, you would need to release it manually. It is a rule of thumb to always return autoreleased objects from functions/methods, so the user of the functions/methods does not have to worry about memory management.

iOS objective-c return object availability/scope

I've read apple documentation to assert that I was doing the memory management correctly but some questions raised.
Question 1:
They exhibit this code snippet as wrong :
in obj implementation:
- (NSString *)method1 {
NSString *string = [[NSString alloc] initWithFormat:#"%# %#", firstName, lastName];
return string;
}
... later ...
NString* myString = [obj method1];
NSLog("%#", myString);
[myString release];
Apple Doc :
You own the string returned by alloc, but lose the reference to it before you get a chance to relinquish ownership. Following the memory management rules, this would result in a memory leak, since the caller has no indication that they own the returned object.
Since I'm taking care of releasing the object that has been allocated previously, there is no memory leak, right ? What do they mean by "lose the reference to it" ?
It is wrong only regarding apple's memory management recommendations (the caller has no indication that they own the returned object) or this is also technically wrong ?
Question 2 :
This is about autoreleased objects availability :
Example code:
in obj1 implementation:
- (NSString *)methodA {
NSString *string = [[NSString alloc] initWithFormat:#"%# %#", firstName, lastName];
return [string autorelease];
}
in obj2 implementation:
- (NSString *)methodB:(NSString *)inputString {
NSLog("%#",inputString)
//*other call of methods with arg inputString*//
}
... later ...
NString* myString = [obj1 methodA];
[obj2 method2:myString];
How far (or deep) following my functions calls will the autorelease object returned by obj1 will be available. Regarding apple's documentations "Autorelease objects will be available within their variable scope". Should I retain it at some point ?
Q1: It is wrong only regarding apple's memory management recommendations (the caller has no indication that they own the returned object) or this is also technically wrong ?
Technically this is correct as you release myString after using it. However if you follow Apples guidelines for method naming (strongly recommended), this is clearly wrong:
You own any object you create.
You “create” an object using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy).
method1 doesn't contain create, alloc, new or copy - thus per the guideline the caller doesn't own the object and doesn't have to release it.
Q2: How far (or deep) following my functions calls will the autorelease object returned by obj1 will be available. Regarding apple's documentations "Autorelease objects will be available within their variable scope". Should I retain it at some point ?
Auto-released objects will be alive until the closest Autorelease Pool is drained, see Autorelease Pools:
An autorelease pool is an instance of NSAutoreleasePool that “contains” other objects that have received an autorelease message; when the autorelease pool is deallocated it sends a release message to each of those objects. An object can be put into an autorelease pool several times, and receives a release message for each time it was put into the pool. Thus, sending autorelease instead of release to an object extends the lifetime of that object at least until the pool itself is released (the object may survive longer if it is retained in the interim).
...
The Application Kit automatically creates a pool at the beginning of an event cycle (or event-loop iteration), such as a mouse down event, and releases it at the end, so your code normally does not have to worry about them. There are three cases, though, where you might use your own autorelease pools:
...
So, if you need your instances to stay alive after the corresponding autorelease pool was drained, take ownership by retaining them. Otherwise you usually just let them be handled by the pool.
Since I'm taking care of releasing the object that has been allocated previously, there is no memory leak, right ?
right
What do they mean by "lose the reference to it" ?
you hold no pointers for the object, such that the object may not be accessed in your program.
It is wrong only regarding apple's memory management recommendations (the caller has no indication that they own the returned object) or this is also technically wrong ?
also correct. the static analyzer will prolly cry too
How far (or deep) following my functions calls will the autorelease object returned by obj1 will be available. Regarding apple's documentations "Autorelease objects will be available within their variable scope". Should I retain it at some point ?
this is a little more complex. autorelease pools are stacked upon each other by thread. that's why you must create one when entering a thread or new event loop iteration, and also why it is a good idea to create them explicitly when performing large operations which create many (autoreleased) allocations.
finally the last pool in the stack (for the thread) is destroyed at the end of the run loop's iteration.
if the object is created under an autorelease pool you create explicitly, then you must retain it to use it beyond the lifetime of the pool which it was created in.
similarly, you must formally retain/copy when passing to other threads. typically, this happens immediately - you just create a copy or retain the formal arguments when entering the implementation of the secondary thread.

Reference on when to release in Objective-C

I'm having a recurring problem in Objective-C. I'm either releasing things too many time, or not enough. or perhaps I'm not retaining them enough...
Can someone point me at a good reference that will give me a rule of thumb on when I need to retain and release?
For example:
I remember reading somewhere that some objects come pre-retained, so I need to release them, but not retain them. Which objects are these?
if I alloc an object and only need it in that method, do I need to release it? retain it?
Obviously, if I retained something, I needtorelease it, but beyond that, I get a bit lost.
The rules are generally pretty simple. If you get an object in one of the following ways:
id obj = [[MyObject alloc] init];
id obj = [myObject retain];
id obj = [myObject copy];
id obj = [myObject mutableCopy];
then you need to release it at some point -- in the same method, or your dealloc method, generally. In other words, balance your calls to alloc, retain, copy, and mutableCopy with a matching release call.
I remember reading somewhere that some objects come pre-retained, so I need to release them, but not retain them. Which objects are these?
This happens rarely. The documentation for the called method should specify that you are responsible for releasing the returned object; otherwise, you should assume you're receiving an autoreleased object.
if I alloc an object and only need it in that method, do I need to release it? retain it?
Yes, you need to release it (but you don't need to retain it). (You can also use one of the convenience methods that return an autoreleased object if you're only going to use it in that method.)
There is one and only one canonical reference: Apple's Memory Management Guide for Cocoa or iPhone.

Memory Management Autorelease vs. Alloc Question

3 correlated questions:
1.Do the code snippets below provide the very same results in terms of memory?
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
bundle=nil;
and
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSBundle *bundle=[NSBundle mainBundle];
[pool drain];
pool=nil;
bundle=nil;
2.Why in
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
the retainCount of bundle is 1, not 0?
3.Which is recommended: always use class methods, or always gain ownership by using alloc?
Thanks.
Yes, those should be equivalent in terms of memory management, from the developer's point of view. The frameworks might be doing something behind the scene to hang on to [NSBundle mainBundle], but that's not your concern.
Ignore retainCount. waves hand That's not the method you're looking for. Once you have relinquished ownership of an object, either by invoking release or autorelease, then it is invalid (bad practice) to send more messages to that object. In your example, you alloc an NSBundle, so you own it. That means it has a +1 retain count (I say +1, because it's relative). When you release the bundle, it now has a "0" retain count, which means you no longer own this object (despite whether or not it may still exist in memory), which means you should not send messages to it, under penalty of stuff blowing up in your face.
What's recommended is to use whatever's appropriate for the situation. If you just need a temporary object, then using a class method that returns an autoreleased object is probably going to be just fine. If you need to be absolutely sure that the object isn't going to go away while you're using it, then you can use an alloc/init approach (or retain an autoreleased object) and then just release it when you're done.
In the second example you will create 1 extra object (the NSAutorealeasePool) and because of that the two are not exactly the same in terms of memory. But after the code runs I believe the memory will return to the same state in both examples. I am not really sure but I believe that in the second example bundle is an autoreleased object, so when the pool is drained it gets released.
I believe that when the object gets dealloc'ed the retainCount isn't changed.
It is usually recommended to avoid class methods when you create a lot of temporary objects because they won't get released until the next AutoreleasePool drain is called (and if you don't have an AutoreleasePool inside your method it won't happen for sure until you return from your method - and maybe even later). Otherwise you should use the one that feels better for you. I personally prefer allocating them. It is also important to remember that if you want the autoreleased object (the one returned from a class method) to stick around even after you return from the function to retain it.