This question already has answers here:
Acceptable ways to release a property
(4 answers)
Closed 8 years ago.
When I create a variable I want to assign to a property I can do the following (assuming the property is #property (nonatomic,retain) UILabel *myLabel;):
UILabel *temp = [[UILabel alloc] init];
self.myLabel = temp;
[temp release];
What would happen in the following scenario where temp is not used?
self.myLabel = [[UILabel alloc] init];
[myLabel release];
This is assuming I would add a [myLabel release]; in dealloc due to the property.
Would this be proper memory management? In the second example does myLabel have a retain count of 2 after the init line?
The second might happen to work, but is incorrect. The first line calls setMyLabel:. That may happen to set an ivar, it may not. It might do all kinds of things (it might make a copy, it might store the information elsewhere, etc). Your second line releases an ivar. If the setter happens to be implemented the way you're assuming, then you will get lucky and it will work. But this is not correct memory management.
The first example is correct. You can also use the autorelease pool to simplify things. Better is to move your code to ARC, which solves all of these problems faster and more easily.
Assigning to a retain property will automatically call retain on the object assigned to (and call release on the previous object). So yes, after
self.myLabel = [[UILabel alloc] init];
[myLabel retainCount] will return 2, one from init and one from assigning the property. So you should either add autorelease to the line above, or call release before the function exits.
Related
I have been working with Objective-C for a month approximately but regretfully I'm still a complete dummy in memory management so I need your advice. I pass an array from one file to the other like this
BidView *bidView = [[[BidView alloc] init] autorelease];
NSLog(#"%i",[bidView.seatsForTableCreated retainCount]);
bidView.seatsForTableCreated = [NSArray arrayWithArray:seats];
NSLog(#"%i",[bidView.seatsForTableCreated retainCount]);
[self.navigationController pushViewController:bidView animated:YES]; `
NSLog tells me that retain count of seatsForTableCreated has raised from zero to two. Then, when I quit the BidView screen (without doing anything with seatsForTableCreated array) I' m doing the following:
NSLog(#"%i",[seatsForTableCreated retainCount]);
[seatsForTableCreated release];
NSLog(#"%i",[seatsForTableCreated retainCount]);
it's quite unclear for me. Now NSLog tells me (both times) that retain count is 1. Then I repeat this procedure (running the same application I mean) and each time things are the same:0-2-1-1. So my questions are:
1)Why 0 to 2? Why retain count increases to 2 not to 1?
2)why then it drops to 1 without being impacted in any way?
3)Why it still remains 1 after i've released it?
4)How would you manage the memory in such a case?
Great thanks in advance
First and foremost. Don't call nor use retainCount for nothing, think about this property as private and only the OS can call. To check if you have a memory leak you should use Instruments.
Seems like you've created an autoreleasing ([NSArray arrayWithArray:seats]) object, so you can't manually release it.
And use the Allocations Instrument to really check if you have a memory leak.
My advice assumes you are using Xcode 4+ and you are not using ARC,
command+shift+B will analyse your memory management (and dead stores and such). I think you got it right. Don't worry about the retain counts so much until you get a complaint from Analyze or find leaks with Instruments. I am not sure how reliable retain counts are. I have seen comments on SO saying not to rely on them.
You are following the rules well
New, Alloc, Copy, Retain --> You will need to release this object when you are done with it.
I am also assuming in BidView.h your property is declared as
#property(nonatomic, retain) NSArray * seatsForTableCreated;
So releasing that in the dealloc method in BidView.m is good memory management
EDIT
It works when even though you don't allocate seats for table created because.
self.seatsForTableCreated = ... will retain whatever object you are setting there.
So if you have a property with (retain) in the declaration, you can consider
self.property = object;
as setting property and retaining it. The properties were added to objective-C to reduce similar code being in every class.
A property in .h
#property (nonatomic,retain) NSObject * property; // don't name your properties property..
Compiler will create 2 methods for you automatically when you #synthesize in the .m
-(void)setProperty:(NSObject*)newP
{
[newP retain]; // retains the new object so it sticks around for line 3
[property release]; // releases previous property
property = newP; // set the property to the object retained in line 1
// property is now same as newP and you are responsible for releasing it
// -(void) dealloc is where you should release it
}
// Note, the compiler may not create the exact same code as above when creating the //setProperty method. If it does, it could be subject to change.
-(NSObject*)property
{
return property;
}
I tried to figure out why Analyze isn't catching the issue when you don't release your property, but haven't. That is confusing and I want to explore it further.
I often see something like:
NSArray *tmpArr = [[NSArray alloc] initWithObjects:#"Info", nil];
self.userInfo = tmpArr;
[tmpArr release];
instead of:
self.userInfo = [[NSArray alloc] initWithObjects:#"Info", nil];
Does anyone know why the top code sample is more popular? Is it more correct memory management than the second?
Second code snippet causes a memory leak due to the array not being released. In most cases properties of object types (like NSArray in this case) are either retain or copy properties and this means they either increase the reference count of the assigned value or copy the whole object. Then the local variable can be (and should be) released if it's not needed anymore.
Non-leaking alternative to the second code snipped would be using autorelease:
self.userInfo = [[[NSArray alloc] initWithObjects:#"Info", nil] autorelease];
or simply:
self.userInfo = [NSArray arrayWithObjects:#"Info", nil];
Assuming that the property userInfo is marked retain, the second form will leak memory. [[NSArray alloc] initWithObjects] will create an array with a reference count of one. Assigning it to a retain property will increase the reference count to two and it will never come back down to zero and be released. It can be fixed either by using the first form you listed or by:
self.userInfo = [[[NSArray alloc] initWithObjects:#"Info", nil] autorelease];
so that the auto release will decrement the reference count to one at the next iteration of the run loop. From then when userInfo is cleared, the reference count will go down to zero and the array will be destroyed.
You should also take a look at this question
Apart from any other reasons there might be, it makes the code more readable and helps to prevent errors.
Your two examples are not equivalent, because you forgot to release the newly alloc/init'ed array in the second one. You would have needed
self.userInfo = [[[NSArray alloc] initWithObjects:#"Info", nil] autorelease];
here.
QED first reason ;-P
Moreover, when you create a local variable first, you can build up more complex objects before publicizing them via a property. If, for example, you were using a mutable array here and filled it with some more complex logic, assigning it to the property right away and only when going on filling it up, clients of your class might access the property with its contents being only half ready – a great provision for sporadic and hard to reproduce bugs.
So even though in your case it would not have been strictly necessary to use a local variable (if you either had autorelease'd it our used the new Automatic Reference Couting "ARC", which would have solved the leak issue automatically), in my opinion it is always a good idea to first get everything ready and then make it visible.
Clean code rules :)
Sorry for the newbie question, but I need a NSMutableArray with some NSNumber inside, created dynamically in a for cycle. My code looks like this:
for (...){
NSNumber *temp_number = [[NSNumber alloc] initWithInteger:someNSInteger];
[target_array addObject:[temp_number copy]];
[temp_number release];
}
Is this a correct way to do it? Does it leak?
Thanks! Miguel
Yep, that leaks. You want:
NSNumber *temp_number = [[NSNumber alloc] initWithInteger:someNSInteger];
[target_array addObject:temp_number];
[temp_number release];
So, no copy. The logic is that because you use alloc, you end up owning temp_number. You then add it to the array and the array does whatever it needs to. You've used temp_number for its intended purpose, so you no longer want to own it and release it.
If you were to take a copy, that would create another instance of NSNumber, which you also own, and therefore which you should also release when you're finished with.
In practice, the array (if it's allocated and exists, rather than being nil), will retain the object for itself, but that's an implementation detail specific to that class and not something you should depend upon or even be particularly interested in beyond the contract that says that the objects you add can later be found in the array.
I've run into some unfamiliar Objective-c memory management code. What is the difference between:
// no property declared for myMemberVariable in interface
id oldID = myMemberVariable;
myMemberVariable = [MyMemberVariable alloc] init];
[oldID release];
and:
// (nonatomic, retain) property is declared for myMemberVariable in interface
self.myMemberVariable = [[MyMemberVariable alloc] init];
Thanks!
The second is technically incorrect, but the first probably stems from someone yet to embrace Objective-C 2.0 property syntax. It was added relatively recently if you're a long-time OS X developer (or an even-longer-time NextStep/OS X developer), so you do see people not using it without gaining any benefit or detriment by not doing so.
So the first is basically the same as:
[myMemberVariable release];
myMemberVariable = [[MyMemberVariable alloc] init];
Given that you have a 'retain' property, the correct version with the setter should be:
// this'll be retained by the setter, so we don't want to own what we pass in
self.myMemberVariable = [[[MyMemberVariable alloc] init] autorelease];
In the first example, you've got an instance variable. In the second, a property with auto memory management attributes (as indicated by the retain).
In the first example, you're allocating an object, assigning it to an instance variable, then releasing it. It also appears that you're also leaking the object that was previously assigned to it since you don't explicitly release it. (Maybe it's autoreleased, can't tell here).
In the second example, you're allocating an object, and assigning it to a property that is retaining it. This means you're going to leak it unless you explicitly release/autorelease it.
self.myMemberVariable = [[[MyMemberVariable alloc] init] autorelease];
or
MyMemberVariable *m = [[MyMemberVariable alloc] init];
self.myMemberVariable = m;
[m release];
It's much better to use properties as you get (most) memory management for free. For example, you won't have to worry about freeing a reference before assigning a new one.
The first form does not use properties. I don't see a good reason not to do:
[myMemberVariable release];
myMemberVariable = [[MyClass alloc] init];
Since the old value is definitely not the same as the new one, so there is no chance any old value is released before it can be retained again.
Properties have the advantage that, in newer compilers, they are synthesized by the compiler and simply do the right thing, i.e. they know how to retain the new and release the old value, if the type is one that must be retained or copied. This is not necessary for types like int, float, etc., since these are simple value types.
In other words, if you use dot notation, either on self or on some other object, you access the property and in fact call either the getter or setter methods, depending on the direction of assignment.
If you access the ivar (member variable) directly, you don't have the protection from the property and have to code retain/release yourself.
You can also write your own setters and getters, and then you'll also have to take care of memory management, where it applies. It does, however, give you more flexibility. You could log items, check the validity of the input, update internal state variables, etc.
What is the difference between the following 2 ways to allocate and init an object?
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
and
self.aController= [[AController alloc] init];
Most of the apple example use the first method. Why would you allocate, init and object and then release immediately?
Every object has a reference count. When it goes to 0, the object is deallocated.
Assuming the property was declared as #property (retain):
Your first example, line by line:
The object is created by alloc, it has a reference count of 1.
The object is handed over to self's setAController: method, which sends it a retain message (because the method doesn't know where the object is coming from), incrementing its reference count to 2.
The calling code no longer needs the object itself, so it calls release, decrementing the reference count to 1.
Your second example basically does steps 1 and 2 but not 3, so at the end the object's reference count is 2.
The rule is that if you create an object, you are responsible for releasing it when you're done with it. In your example, the code is done with tempAController after it sets the property. It is the setter method's responsibility to call retain if it needs that object to stick around.
It's important to remember that self.property = foo; in Objective-C is really just shorthand for [self setProperty:foo]; and that the setProperty: method is going to be retaining or copying objects as needed.
If the property was declared #property (copy), then the object would have been copied instead of retained. In the first example, the original object would be released right away; in the second example, the original object's reference count would be 1 even though it should be 0. So you would still want to write your code the same way.
If the property was declared #property (assign), then self isn't claiming ownership of the object, and somebody else needs to retain it. In this case, the first example would be incorrect. These sorts of properties are rare, usually only used for object delegates.
As others have noted, the two code snippets you show are not equivalent (for memory management reasons).
As to why the former is chosen over the latter:
The correct formulation of the latter would be
self.aController= [[[AController alloc] init] autorelease];
Compared with the former, this adds additional overhead through use of the autorelease pool, and in some circumstances will lead to the lifetime of the object being unnecessarily extended (until the autorelease pool is released) which will increase your application's memory footprint.
The other "possible" implementation (depending on where the example is from) is simply:
aController = [[AController alloc] init];
However, setting an instance variable directly is strongly discouraged anywhere other than in an init or dealloc method. Elsewhere you should always use accessor methods.
This brings us then to the implementation shown in sample code:
AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];
This follows best practice since:
It avoids autorelease;
It makes the memory management semantics immediately clear;
It uses an accessor method to set the instance variable.
Note also that your desire to cut the code down to one line is why many people use Autorelease:
self.aController = [[[AController alloc] init] autorelease];
Though in theory on the iPhone autorelease is somehow more expensive (never heard a clear explanation why) and thus you may want to explicitly release right after you assign the object elsewhere.
If you're using Xcode, it can help you detect such code with the static analyzer.
Just hit Build >> Build and Analyze
This will show you a very helpful message at such pieces of code.
One other thing to note is that your example depends on the #property definition of aController also.
If it were defined as #property (readwrite, retain) id aController; then your example works, while if it is defined as #property (readwrite, assign) id aController; then the extra call to release would cause your object to be deallocated.
You could also do
#property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];
with a retaining property, and it would function the same way, but its better to use the other way (for retaining properties) because it's less confusing, that code makes it look like you assign aController and then it gets deleted from memory, when actually it doesn't because setAController retains it.