What's the difference between an [[alloc]init] and a [[thing]retain]? - objective-c

I was wondering, what (if any) is the difference between creating objects using:
NSThing *thing = [[NSThing alloc] initWithObject:object];
vs
NSThing *thing = [[NSThing thingWithObject:object] retain];
Is there a difference in how the memory management works? Also, when is it common practice to use one vs the other?

Allocating and initialising an object is slightly more efficient, because thingWithObject: will do an alloc, then init, then autorelease which you counter with a retain, so you add something to the autorelease pool. The first option only involves an alloc and a init.
Personally, I use the explicit alloc when I want to be clear that the object's lifetime will be handled by me, and I use the convenience methods (thingWithThing:) for any object that I won't need outside of the scope it is created in.
For example, explicitly allocating and initialising within a loop is generally preferred, so that you don't flood the autorelease pool. I also use an explicit alloc+init rather than thingWithThing: + retain for objects that need to survive an iteration of the run loop.

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.

Is AutoRelease redundant when using ARC in Objective-C?

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.

Using autoReleased objects without an NSAutoReleasePool?

I'm writing my very first steps in Objective-C.
I followed some examples and the official documentation, and am using autoreleased objects* without explicitly declaring an NSAutoReleasePool.
* By autoreleased objects I mean: SomeClass *obj = [SomeClass someClass];
Is it ok to do it this way?
Will it cause a memory problem?
Is declaring a NSAutoReleasePool more efficient?
edit: I made a mistake in the code example, what I meant was getting an object by it's class factory method instead of allocing an instance of it. This factory methods [often|always] return autoreleased objects, right? for example: [NSString stringWithCString:x]
You don't need to create an autorelease pool explicitly usually. When you do normal Mac programming using the AppKit framework, there will be an implicit autorelease pool which is handled by the event loop. You need to concern yourself with autorelease pools mainly on two occasions:
Your code runs in a background thread: If you have a background thread there is no autorelease pool created for you and you will have to do this manually.
You have a tight loop where you create and destroy a lot of objects. If in this loop any objects are autoreleased they will not actually be released until the autorelease pool is drained. This means that your memory consumption will rise, even though you don't reference those objects anymore. In this situation having a local autorelease pool can help with performance, although switching from autoreleasing to explicit retain/release is probably more efficient.
In answer to your question: that's a no-no. You will leak memory if you autorelease an object (or use an autoreleased object) in a scope that has no autorelease pool.
perhaps ignore the following:
With regard to your example, it might be rather confusing the way you've written it, since Class is a typedef of struct objc_class*. So, you're really declaring a pointer-to-a-pointer to a class, and then assigning a pointer to a class to it. Which won't work. Moreover, since Class is not an Objective-C “class-type” per se, you can't send messages to it.
But all this is neither here nor there, since ±class does not return an autoreleased object.

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.

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

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).