This is an example straight from Apple's documentation -
#implementation MyClass
- (id)initWithString:(NSString *)aName
{
self = [super init];
if (self) {
name = [aName copy];
}
return self;
}
+ (MyClass *)createMyClassWithString: (NSString *)aName
{
return [[[self alloc] initWithString:aName] autorelease];
}
#end
As I would be creating a new MyClass Object in each case anyway, I want to know why I might use the Class Method createMyClassWithString:aName instead of the Instance Method initWithString:aName
Thanks
I always use the class method where possible because it results in less verbose code and if you are simply going to return the object to the caller you'd have to autorelease it anyway, if you obtained it with alloc.
The advice from Apple was poorly worded, in my opinion. People seem to be taking it as a blanket ban on autorelease. That's simply not the case. You just have to be mindful that autorelease comes withy a memory price, but it is not as high as you might think. Each runloop event except timer events comes with a new autorelease pool that gets drained on return to the runloop. So if you know the method is going to be quick there's no problem. Also, if an object is going to outlive the current event, there's no issue because the overhead ofd an object in an autorelease pool is quite small and draining the pool won't dealloc the object anyway.
The only case where you need to be careful about putting objects indiscriminately in the autorelease pool is where you have intensive processing creating lots of temporary autoreleased objects. You can relieve the pressure of these methods by creating autorelease pools and draining them as you go along. e.g.
while(someCondition)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// intensive processing
[pool drain];
}
The only reason is readable and beautiful code...
In addition, in your example the class method returns an autoreleased instance...
The short, unhelpful answer would be: where is makes sense. Neither is more correct; neither is wrong.
An example might be more use. I would use the class method if I was returning the value from a method:
- (MyClass*) doStuff {
MyClass* retv = [MyClass createMyClassWithString:#"Simon says"];
[retv someOtherMethod];
return retv;
}
By convention you return autoreleased objects, so using the class method results in slightly less typing.
Related
I understand that when using Alloc, new or copy you own the object and need to release the object. I understand that if I retain an object that I need to release it.
But if I have the following statment at the end of a method:
return [[UIImage alloc] initWithContentsOfFile:path];
I own the UIImage object becaused I allocated the memory space, but I dont have a reference to it anymore because it was returned to the caller. In my dealloc() method I can't release it, since I dont have a reference.
So my question is, is this correct:
return [[[UIImage alloc] initWithContentsOfFile:path] autorelease];
I beleive in this case the caller then can retain the returned object if they like to take ownership and will eventually need to release themselves.
Thanks for your help.
Your assumptions are right. When you're returning an object, you should pass it as an autorelease object.
You use autorelease when you need to send a deferred release message—typically when returning an object from a method...
The whole point of autorelease was built around returning objects.
- (id)bad {
MyObj *obj = [[MyObj alloc] init];
return obj;
}
This code returns everything correctly, but you (as developer) must be sure to release the object later on.
- (id)moreBad {
MyObj *obj = [[MyObj alloc] init];
return [obj release];
}
This code uses the memory as expected, balancing retain and release in one scope, but returned object is garbage now (expect this to crash).
- (id)good {
MyObj *obj = [[MyObj alloc] init];
return [obj autorelease];
}
This code is "delayed release". I.e. you can retain the object at the caller side and the object would be safe. It could surely be broken if you don't have NSAutoreleasePool in scope, but that's a pretty rare condition, and you mostly know when that happens (the most common scenario is to start a new thread where there is no "default" autorelease pool).
So, the common practice is to balance the retain (and retain-like) and release methods in one scope. Next suggestion is to always have objects alloc-init-autoreleased, and switch to distinct releases if you have memory issues (like autoreleasing lots of objects in a loop). Next suggestion is to switch to ARC.
Both answers are correct, you may however not always have a convenience method at your disposal, so what I like to do is what you've done with autorelease:
- (MySomethingClass*)giveMeAFancyObject{
MySomethingClass *obj = [[[MySomethingClass alloc] init] autorelease];
obj.name = #"Something";
// do some setting up maybe
return obj;
}
If you use release, however, the string will be deallocated before it is returned (and the method would return an invalid object). Using autorelease, you signify that you want to relinquish ownership, but you allow the caller of the method to use the returned string before it is deallocated.
Why trying to alloc it? Just say:
return [UIImage imageWithContentsOfFile:path];
Nothing to alloc - nothing to release.
Also, this is the best option while using ARC, where a releasing attempt leads to error.
Could someone help me please understand how allocation and memory management is done and handled in following scenario. i am giving a Psuedo code example and question thats troubling me is inline below:
interface first
{ NSDecimalNumber *number1;
}
implementation
.....
-(void) dealloc {
[number1 release];
[super dealloc];
}
=================================
interface second
{ NSDecimalNumber *number2;
}
implementation second
.....
- (First*) check
{
First *firstObject = [[[First alloc] init] autorelease];
firstObject.number1 = [[NSDecimalNumber alloc] initWithInteger:0];
**// do i need to autorelease number1 as well?**
return firstObject;
}
Your code is correct as is. If you autoreleased the object, its reference count would reach zero and it would be dealloced, and then if you later tried to use the value stored in number1 your app would crash.
The only enhancement I'd add is releasing any existing value. i.e.
[number1 release];
number1 = [[NSDecimalNumber alloc] initWithInteger:0];
If you don't do this, the previous object assigned to number1 will leak each time check is called.
As you're allocing the NSDecimalNumber, you need to release it. (As you're doing so in the dealloc.)
Whilst it's hard to provide a meaningful example based on your sample code (as "number1" isn't actually used), the general rule is that you're responsible for any object you alloc, copy or new. If the object was only required in the scope of a function, you could of course autorelease it.
There's a good blog article over at http://interfacelab.com/objective-c-memory-management-for-lazy-people/ that I'd recommend reading as it provides good examples (including some edge cases) and is easy to follow.
In my code, I use a singleton object as a central point in my app to load and cache images the app frequently needs, so I don't have to do resource-intensive memory allocation each time I load an image.
But there are times during the execution of my app where memory usage gets intense and I would like to release the cached image data. Currently, I'm just releasing the UIImage instances from my singleton when I get a memory warning.
I would prefer, however, to be able to release the entire singleton object. Is that possible? If so, how?
Of course it is. Although it's rather likely that the memory usage of this object is negligible compared to the images.
By the nature of a singleton, you need to have an accessor for it, where you will create it if it does not currently exist:
+ (MySingletonClass*) mySingleton
{
if ( mySingleton == nil )
{
mySingleton = [[MySingletonClass alloc] init];
}
return mySingleton;
}
You just need to add another that you call when you want to destroy it:
+ (void) destroyMySingleton
{
[mySingleton release];
mySingleton = nil;
}
If you keep references to it around elsewhere you'll have trouble; don't do that. If you access from multiple threads you'll need to synchronize. Otherwise, it's pretty straightforward -- the getter will recreate when you next need it.
Here's an example of a singleton accessor for the OpenAL code I'm using.
// Eric Wing. Singleton accessor. This is how you should ALWAYS get
// a reference to the sound controller. Never init your own.
+ (OpenALSoundController*) sharedController
{
static OpenALSoundController* shared_sound_controller;
#synchronized(self)
{
if (nil == shared_sound_controller)
{
shared_sound_controller = [[OpenALSoundController alloc] init];
}
}
return shared_sound_controller;
}
OpenAL takes a while to load up so keeping one instance around is exactly what I need. With more than one thread in play (not my situation currently but I want my code to be ported to situations where this is the case) I put a lock on self. #synchronized(self) does exactly that.
Now I allocated the memory so I'm responsible for releasing it. I could call [shared_sound_controller autorelease] in the +sharedController accessor method but this may release the controller early, particularly when I have more than one thread and I call the accessor for the first time in a thread that's not the main thread.
Any object you create you can just release at any time. (Presuming you create it and set it's properties.)
self.myObject = [[myObjectClass alloc] init];
// do something with the object
[self.myObject release]; // anytime that you are not using the object
self.myObject = nil; // will also work if you've set the #property (retain, nonatomic)
I'm following a book on iPhone development and there is a particular pattern I keep seeing in the example code that doesn't make much sense to me. Whenever a property is set they first assign a pointer to the new value for the property, then set the property to the pointer, then release the pointer. Example:
Interface:
#interface DoubleComponentPickerViewController : UIViewController {
NSArray *breadTypes;
}
#property(nonatomic, retain) NSArray *breadTypes;
#end
Class method:
- (void)viewDidLoad {
NSArray *breadArray = [[NSArray alloc] initWithObjects:#"White", #"Whole Wheat", #"Rye", #"Sourdough", #"Seven Grain", nil];
self.breadTypes = breadArray;
[breadArray release];
}
Is there any reason to do this instead of just doing the following?
- (void)viewDidLoad {
self.breadTypes = [[NSArray alloc] initWithObjects:#"White", #"Whole Wheat", #"Rye", #"Sourdough", #"Seven Grain", nil];
}
Thanks for the light that will no doubt be shed :)
Let me try and explain it in a different way.
A method that has alloc, copy or new in its name will allocate memory for an object, and gives ownership of that object to the caller, and it is the caller's responsibility to release that memory.
In your viewDidLoad method, you call a method that gives you ownership of an object. It is your method's responsibility to release it. However, before you do that, you want to do something with it - after all, that's why you alloc'ed it, not to just release it, but to do something useful with it.
Regardless of what it is that you want to do with it, you have to release it (or autorelease it*). In this case your use of the object is to pass it to self.breadTypes. self.breadTypes may not look like a method, but it is (it is a setter). You pass it breadArray. It does what it needs to with it. It might retain it for use later, or it might copy some info out of it, or make a copy of the entire thing. Your viewDidLoad doesn't really care. It assumes that self.breadTypes does what it needs to and when it returns, it doesn't care what you do with breadArray.
And what you do with it, is what you have to do with anything that you own - release (or autorelease* it).
That's why you have to use the temp variable, breadArray. You can't quite release the results from alloc on the same line, since the object would get released before self.breadTypes can have at it:
self.breadTypes = [[[NSArray alloc] initWithObjects:#"White", ..., nil] release];
Thus you are forced to assign to a temp variable, pass it to self.breadTypes, and then release the object that is saved in breadArray.
Now, you could try to do it this way so you don't use a temp variable:
- (void)viewDidLoad {
self.breadTypes = [[NSArray alloc] initWithObjects:#"White", #..., nil];
[self.breadTypes release];
}
but that is not very efficient since you are calling yet another method (self.breadTypes as a getter) that you didn't really need to if you have just stored the value in a temp variable.
*Now, as a responder said, you could use autorelease for an alternative version:
- (void)viewDidLoad {
self.breadTypes = [[[NSArray alloc] initWithObjects:#"White", ..., nil]
autorelease];
}
Apple urges us to think twice about whether we want to use autorelease vs. release. Autorelease may not be the best choice for every situation. I personally like to clean up after myself as soon as I possibly can, and not use autorelease needlessly. Autoreleased objects get released at the end of the execution of the run loop, for example soon after viewDidLoad returns. You should read up a bit more about autorelease (and memory management on the iPhone which is slightly different than MacOS X Cocoa), as I am oversimplifying it all.
BTW: If you retain an object, you are assuming ownership of it, and you will have the same responsibility again, to release it after you are done with it.
Yes. Those methods are alloc'ing the variables so they must be released. The fact that the property has a retain attribute means that when you say #synthesize breadTypes; the compiler is actually generating a setBreadTypes that properly releases the current breadType member and retains the new one. Thus your function must not retain the variable it alloc'ed.
You could, however write:
- (void)viewDidLoad {
self.breadTypes = [[[NSArray alloc] initWithObjects:#"White",
#"Whole Wheat", #"Rye", #"Sourdough",
#"Seven Grain", nil]
autorelease];
}
You'll want to brush up on Cocoa Memory Management
Still a little confused about Objective-C memory management. I think my confusion stems from what exactly the autorelease means.
NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];
Now, what should I do with the accountDictionary in the setAccountDictionary method of my view controller? Right now I just set the instance variable "accountDictionary" to whatever is returned. Should I set it to a retained one, and then release the one that's returned? What should my setter code block look like, given that NSString's propertyList method is autoreleased?
By the way, if I release theBackendResponse, will I lose the accountDictionary? I assume not...
Calling [objectInstance autorelease] adds an object to the current NSAutoreleasePool. When that pool receives a drain message, it sends a release to all the objects in the pool. If any of those objects' retainCount reaches 0, they are deallocated at that point. The purpose of autorelease is to allow you to mark an object to be released "some time in the future". This is especially useful for things like methods that return a newly allocated object but want to release it so that the caller doesn't have to take ownership of the returned object. A method might look like this:
- (id)myMethod {
id myObj = [[SomeClass alloc] init];
...
return [myObj autorelease];
}
The caller of myMethod would then retain the return value if they wanted to take ownership of the returned value or ignore it if not. When the current NSAutoreleasePool is drained, myObj will get a release message. If no other objects own it (i.e. have sent it a retain message), it will get deallocated.
All of this is explained in the Cocoa Memory Management Programming Guide. Even if you've already read it, it's always worth an other read.
So, to answer your questions:
First, you should release theBackendResponse. You will leak memory if you do not. You don't need to know what accountDictionary does with the string: if it needs to keep a reference it will have retained theBackendResponse. You have an ownership of theBackendResponse because you alloc'd it, so you must relinquish that ownership (via release or indirectly via autorelease).
Second, you must retain or copy the argument to setAccountDictionary: if you want to keep a reference to that object or value respectively. The standard setter method looks something like this (assuming you do not need atomic semantics):
-(void)setAccountDictionary:(NSDictionary*)newDict {
if(newDict != accountDictionary) {
id tmp = accountDictionary;
accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
[tmp release];
}
}
You must also remember to release accountDictionary in the dealloc method:
- (void)dealloc {
[accountDictionary release];
[super dealloc];
}
Since you appear to be using NSViewController, I assume you're on Leopard (OS X 10.5) in which case, you should probably be using #property and the #synthesized getter/setter if possible. To do this, add a
#property (copy,readwrite) NSDictionary * accountDictionary;
declaration to the class #interface. And add a #synthesize accountDictionary; directive in the #implementation block for your controller class.
In general, one object or method should not have to care about how another is managing memory. The fact that somebody else has autoreleased something is irrelevant to you. It's simpler to think of the concept of ownership. So retain and some other methods claim ownership, and release and autorelease relinquish it. If an object needs to keep a reference to another, it should claim ownership for as long as it needs. Thus, setter methods usually either retain or copy the new value and release or autorelease the old value.
I strongly recommend reading the Cocoa memory management guidelines. They're not all that long or complicated, and it's very important to understand them.
The set accessor method should always copy / retain the incoming value before releasing the old, in the case where the old value is the only object that owns the new value:
-(void)setAccountDictionary:(NSDictionary*)newDict {
id old = accountDictionary;
accountDictionary = [newDict copy];
[old release];
}
If accountDictionary referred to newDict and the retain count for newDict was 1, the call to [accountDictionary release] before the call to [newDict copy] would cause the retain count to got to 0 and therefore release newDict.
As an example of incorrect code, where we release the old dictionary and then copy the new dictionary:
-(void)setAccountDictionary:(NSDictionary*)newDict {
[accountDictionary release];
accountDictionary = [newDict copy];
}
and have the following code:
NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];
It's contrived, but it demonstrates that in the setter, accountDictionary and newDict refer to the same instance. If the retain count is 1, the [accountDictionary release] line will decrease the retain count to 0, and thus release the instance from memory. [newDict copy] will now refer to an invalid instance.
Apple describes several concepts when implementing accessors: Memory Management Accessor Methods
If you can use Objective-C 2.0, I would go with properties and dot syntax.
Properties are new in Objective-C 2.0 and provide auto accessor generation.
In the .h File:
#property (retain) NSDictionary* accountDictionary;
In the implementation:
#synthesize accountDictionary;
Synthesize generates accessor methods for your NSDictionary. (If you want to provide your own implementation, you could also do that)