Why do we need a temporary object? - iphone

As I have seen in many examples, first they allocate memory for the temporary object and later the same object is assigned to self. For example, I have a code snippet here :
-(void)viewDidLoad {
[super viewDidLoad];
Movie *newMovie = [[[Movie alloc] initWithTitle:#"Iron Man"
boxOfficeGross:[NSNumber numberWithFloat:650000000.00]
summary:#"Smart guy makes cool armor"] autorelease];
self.movie = newMovie;
}
Why cant we perform like:
self.movie =[[[Movie alloc] initWithTitle:#"Iron Man"
boxOfficeGross:[NSNumber numberWithFloat:650000000.00]
summary:#"Smart guy makes cool armor"] autorelease];

Both are essentially the same. They adhere to the ownership clause – You release what create/retain. The difference, though not so obvious here, is that the time it takes for an autoreleased object to be released. Say, if loads of such autoreleased objects lingered around in the memory, this could create memory problems. If we released them and their retain count is zero, they are immediately deallocated and memory is freed up.

You don't need the temporary object. Your suggestion is perfectly valid.

However, if you need to set properties or call methods after creating the object, using a temporary object may be a little nicer than calling self.movie multiple times:
Movie *newMovie = [[[Movie alloc] initWithTitle:#"Iron Man" boxOfficeGross:[NSNumber numberWithFloat:650000000.00] summary:#"Smart guy makes cool armor" ] autorelease];
newMovie.rating = 4;
[newMovie fetchImageFromServer];
self.movie = newMovie;
Personally, I do not use autorelease in that scenario, but that's more a style preference:
Movie *newMovie = [[Movie alloc] initWithTitle:#"Iron Man" boxOfficeGross:[NSNumber numberWithFloat:650000000.00] summary:#"Smart guy makes cool armor" ];
newMovie.rating = 4;
[newMovie fetchImageFromServer];
self.movie = newMovie;
[newMovie release];

Related

IPhone Objective C Memory Allocation

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.

How to release an object in a forin loop?

I'm new to cocoa / objective-c and i'm struggeling with the releases of my objects. I have the following code:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
}
The analyzer shows me that the "gastrocategory" defined in the for is a potential memory leak. But i'm not sure if i can release this at the end of the for loop?
Also at the following code:
- (NSArray *)eventsForStage:(int)stageId {
NSMutableArray *result = [[NSMutableArray alloc] init];
for (Event *e in eventList) {
if ([e stageId] == stageId) {
[result addObject:e];
}
}
return result;
}
The Analyzer tells me that my "result" is a potential leak. But where should I release this?
Is there also a simple rule to memorize when i should use assign, copy, retain etc. at the #property ?
Another problem:
- (IBAction)showHungryView:(id)sender {
GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:#"GastroCategoriesView" bundle:nil];
[gastroCategoriesView setDataManager:dataManager];
UIView *currentView = [self view];
UIView *window = [currentView superview];
UIView *gastroView = [gastroCategoriesView view];
[window addSubview:gastroView];
CGRect pageFrame = currentView.frame;
CGFloat pageWidth = pageFrame.size.width;
gastroView.frame = CGRectOffset(pageFrame,pageWidth,0);
[UIView beginAnimations:nil context:NULL];
currentView.frame = CGRectOffset(pageFrame,-pageWidth,0);
gastroView.frame = pageFrame;
[UIView commitAnimations];
//[gastroCategoriesView release];
}
I don't get it, the "gastroCategoriesView" is a potential leak. I tried to release it at the end or with autorelease but neither works fine. Everytime I call the method my app is terminating. Thank you very much again!
In your loop, release each gc after adding it to the list since you won't need it in your loop scope anymore:
gastroCategoryList = [[NSMutableArray alloc] init];
for (NSDictionary *gastrocategory in gastrocategories) {
NSString *oid = [gastrocategory objectForKey:#"id"];
GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:#"name"]];
[gastroCategoryList addObject:gc];
[gc release];
}
In your method, declare result to be autoreleased to absolve ownership of it from your method:
NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
// An alternative to the above, produces an empty autoreleased array
NSMutableArray *result = [NSMutableArray array];
EDIT: in your third issue, you can't release your view controller because its view is being used by the window. Setting it to autorelease also causes the same fate, only delayed.
You'll have to retain your GastroCategoriesView controller somewhere, e.g. in an instance variable of your app delegate.
BoltClock's answer is spot-on as to the first part of your question. I'll try to tackle the rest.
Assign is for simple, non-object types such as int, double, or struct. It generates a setter that does a plain old assignment, as in "foo = newFoo". Copy & retain will, as their names imply, either make a copy of the new value ("foo = [newFoo copy]") or retain it ("foo = [newFoo retain]"). In both cases, the setter will release the old value as appropriate.
So the question is, when to copy and when to retain. The answer is... it depends. How does your class use the new value? Will your class break if some other code modifies the incoming object? Say, for example, you have an NSString* property imaginatively named "theString." Other code can assign an NSMutableString instance to theString - that's legal, because it's an NSString subclass. But that other code might also keep its own reference to the mutable string object, and change its value - is your code prepared to deal with that possibility? If not, it should make its own copy, which the other code can't change.
On the other hand, if your own code makes no assumptions about whether theString might have been changed, and works just as well whether or not it was, then you'd save memory by retaining the incoming object instead of unnecessarily making a copy of it.
Basically, the rule, which is unfortunately not so simple sometimes, is to think carefully about whether your own code needs its own private copy, or can correctly deal with a shared object whose value might be changed by other code.
The reason you can release gc after it is added to the gastroCategoryList is that when an object is added to an array, the array retains that object. So, even though you release your gc, it will still be around; retained by the gastroCategoryList.
When you are returning a newly created object from a method, you need to call autorelease. This will cause the object to be released only after the runtime leaves the scope of the calling method, thereby giving the calling method a chance to do something with the returned value.
Note that if your method starts with the word copy or new, then you should not autorelease your object; you should leave it for the calling method to release.
As for copy vs retain vs assign... as a general rule, copy objects that have a mutable version, such as NSArray, NSSet, NSDictionary, and NSString. This will ensure that the object you have a pointer to is not mutable when you don't want it to be.
Otherwise, use retain whenever you want your class to be ensured that an object is still in memory. This will apply to almost every object except for objects that are considered parents of your object, in which case you would use assign. (See the section on retain cycles here).
Also note that you have to use assign for non-object types such as int.
Read through the Memory Management Programming Guide a bit; it's quite helpful.

question related to Iphone autorelease usage

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.

(iphone) basic memory management question

I have used following 2 patterns to create a view.
#property (retain, nonatomic) SomeView* someView;
...
// First pattern
self.someView = [[SomeView alloc] initWithFrame frame];
// Second pattern
SomeView* aSomeView = [[SomeView alloc] initWithFrame];
self.someView = aSomeView;
[aSomeView release];
Now, looking back at this code, the first pattern's method should be changed to
self.someView = [[[SomeView alloc] initWithFrame frame] autorelease];
shouldn't it?
I feel dumb :(
Look at it like this:
[[SomeView alloc] initWithFrame: frame];
The above line creates an object and gives it a retain count of 1.
self.someView = [[SomeView alloc] initWithFrame: frame];
This line leaves it with a retain count of two, because the someView property is declared with retain:
#property (**retain**, nonatomic) SomeView* someView;
So, doing it this way leaves your someView property pointing to an object with retain count of 2. You can do it this way if you add an autorelease call to it:
self.someView = [[[SomeView alloc] initWithFrame: frame] autorelease];
Your second pattern is better, if you ask me. You create an object with a retain count of one. You assign it to a retaining property (now it has a retain count of 2) and then you release the original variable, leaving the object again with a retain count of 1. It's three lines where you might want only one, but it makes sense in the right context. Additionally, it's usually best to avoid using autorelease outside of an alloc or copy method since its usually an indication you don't fully understand memory management in Obj-C.
And as a commenter said in the comments to the question, don't feel dumb. None of this is intuitive at first. Nobody picks up a guitar and plays like Hendrix their first time.
Yes, you are right. autorelease means "release a bit later".
Yes, I think you should change that. With self.someView = you are calling the setter which increases the retain count.
Now, looking back at this code, 1's method should be changed to self.someView = [[[SomeView alloc] initWithFrame frame] autorelease];
shouldn't it?
correct
a)
SomeView * view = [[SomeView alloc] initWithFrame:frame];
self.someView = view;
[view release], view = nil;
b)
self.someView = [[[SomeView alloc] initWithFrame:frame] autorelease];
many people prefer b, simply because it is less to type.
i prefer an approach similar to a because:
defects (such as over-releasing) are often exposed near the call site, rather than when the pool is destroyed (this often means you have to load up Instruments in Zombie mode to locate the callsite)
it performs better and minimizes memory usage (in general, but not much in this specific case)
you have more opportunity to check for invalid states and results
you have a chance to init/configure the view/object for its usage before adding it to self, which is usually preferred

Unnecessary temporary variables when setting property values?

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