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.
Related
I am a C programmer, but is pretty new to Objective-C. I've seen NSString-related code like this several times:
NSAppleScript* script = [[NSAppleScript alloc] initWithSource: #"<some script code>"];
...
[script release];
The above code explicitly releases the NSAppleScript object, but doesn't seem to release the NSString object anywhere.
I wondered if the [script release] automatically does the job of implicit release of the NSString object, so I changed the above code to the following:
NSString* scriptText = #"<some script code>";
NSAppleScript* script = [[NSAppleScript alloc] initWithSource: scriptText];
...
[script release];
//If [script release] has implicitly released scriptText,
//this would cause a repeated release.
[scriptText release];
But the above code turned out running also well. Does it mean that [script release] doesn't automatically release the NSObject object? In other words, does the code in the first section leak release of the NSString?
Very short answer: no. You shouldn't release scriptText. (In fact, you must not.)
In ObjC manual reference counting, you need to follow the rules, which are based on method names. If you call a method whose name begins with alloc or new or includes copy, then you are responsible for calling release or autorelease on the object that is returned to you. Also, if you call retain on an object, you are responsible to call release or autorelease.
Following the rules, you called +[NSAppleScript alloc], so you are responsible for calling release on the object returned to you. You did not call a retaining method to get scriptText; you used an NSString literal (#"..."). So you must not call release on it. It doesn't leak. (If it did, it would indicate a bug in Apple's code.)
The way this actually works is that NSString literals are stored directly in the binary, just like in C. There is no need to manage them, since they do not directly use memory. But this has nothing to do with your obligations under manual reference counting. You shouldn't think "this is a string literal so I shouldn't call release on it." That's not true at all. You should call release when the rules tell you to call release. It is completely correct to call retain on a value that happens to be a literal, and later call release on it. (This happens all the time. You generally don't know whether the NSString you're working with is a literal or not.)
It happens to be true that calling retain or release on NSString literals does nothing. They just ignore the call. Very short NSString objects don't even exist in memory. If they're short enough, the data is stored directly in the pointer (called a "tagged pointer"). Again, this is just an implementation detail. Your job is to follow the rules, not try to second-guess the system.
(The reason that your incorrect code with the extra release "works" is because literal NSStrings ignore memory management calls. The code is still incorrect. There's also no promise that over-releasing an object will cause a crash in any case, and it is very, very common when it does crash for it to occur at a random point, far away from the mistake. It's very common for objects to have pending autorelease calls on them, so you get a crash when the pool drains, with no hint where your bug is.)
And of course you should turn on ARC and let it handle it for you. It does a very good job. But it's helpful to understand the rules anyway. ARC uses the same name-based rules to figure out where to put retains and releases. That's how it can interoperate seamlessly with manual memory management.
I'm pretty new to Objective-C, as you may gather, and until recently, I hadn't really understood the need for all this AutoRelease malarky. I think that's mostly because I've started Objective-C with ARC, and haven't had any exposure to doing retains and release.
Anyway, my understanding now is that pre-ARC, if you created an object and needed to return a pointer to it as the returning object of the method/function, you would need to autorelease it, because you are unable to do the "[obj release]" after doing "return obj;"
Worrying about retains and releases isn't an issue with ARC. Does this mean that in our own code, there is really point in creating our own autoreleased objects? Ie, doing [[[Class alloc] init] autorelease]? From what I've gathered, we should still setup autorelease pools, but only because other frameworks or libraries may still return autoreleased objects, but we no longer need to explicitly create autoreleased objects ourselves - is this a fair understanding?
Thanks,
Nick
When using ARC, you do not want to do any memory management yourself. Specifically you will not be calling release and auto release because it does it all for you. In fact, the compiler should probably complain if you try to manage memory yourself.
Instead of [[[Class alloc] init] autorelease]; you'll just call [[Class alloc] init];
I recommend reading this blog post for some really good background on ARC and memory management in general.
Well, your understanding is quite correct. With ARC we do not release or autorelease any more. Just have to make sure that we assign nil (or some other reasonable value) to any reference to objects, which we do not need any more. In the worst case we could still constantly consume additional memory but the memory cannot leak any ore.
And yes, we still maintain autorelease pools for the sake of using framework libraries (linked ones) that may not use ARC.
To answer your question between the lines about the purpose of autorelease. This applies to non-ARC project only, of course.
In the good old days Objective-C did not offer any reference counting but its retain counting. Any allocated memory of objects, that are not retained (or have a retain count of 0) is considered free and may soon be claimed and used by other objects.
This means that every object needs to be retained after its allocation, assuming that you want to keep it around. When the object is not used any more then you need to release it. This comes with two risks. Well, alloc does retain it once automatically.
1) You may forget to release an object that is unused. In the worst case you may even loose all references to an object that stays in memory for ever since.
2) You may still refer to an object hat has been released already and then try accessing it which will most likely end in an BAD_EXC exception.
All this can be quite annoying. In order to get rid of some of these obligations for objects that don't stay around very long, the autorelease was invented. For temporary objects only you alloc it (release-count = 1) and autorelease it. That means that the object will be automatically released (retain count reduced by 1) within the next autorelease circle. But the object remains allocated for your method while it is being executed. Typically the reference variable would be a local one.
Sample:
-(void) myMethod{
AClass *someObject = [[[AClass alloc] init] autorelease];
// use the object
// probably hand it to another object if that takes ownership, i.e. add it ot an Array using addObject:
// don't care any more
}
And that not required any more when using ARC.
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.
Can someone explain the difference between these two, the first one is taken from allowing xcode to automatically generate the declaration, the last one is taken from an example in "Cocoa Programming" by Aaron Hillegass.
- (NSString*)planetName {
return [[planetName retain] autorelease];
}
.
- (NSString*)planetName {
return planetName;
}
I am just curious whats going on, my understanding was that the method is returning a pointer to either nil or an existing string object. I don't understand the reason for retaining and then adding to the autorelease pool?
Consider:
NSString *planetName = [myPlanet planetName];
[myPlanet setPlanetName: #"Bob"];
[planetName length];
Without [[planetName retain] autorelease], the above will very likely crash.
retain/autorelease puts the object into the current thread's autorelease pool. That effectively guarantees that the object will remain valid until the pool is drained, which is typically after the current event -- user event, timer firing, etc... -- is done processing.
(1) Use #property and #synthesize. It generates correct getter/setters for you.
(2) Read the Cocoa Memory Management guide. It answers all of these questions quite well.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
In both cases, yes, they are both returning a pointer to either nil or the string object.
The difference is that the first code block handles memory management, the second does not. The second code block is assuming you are managing planetName somewhere else in your class instance, whereas in the first code block Apple is being as conservative as possible in keeping that memory from leaking. By putting the memory in the current autorelease pool it will be destroyed with the pool.
My recommendation would be to stick with the latter case and to be a little wiser about managing your own object instances than what XCode is auto-generating for you.
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).