Balance retain with release? - objective-c

I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
gary

No, but you shouldn't need to do this at all since you are not allocating anything. You could simply return name and that should be fine. Was there a reason you needed to add this retain/autorelease?
A little more explanation, what is happening here is that your retain count goes up by one when you do a retain, and then down by 1 when the scope exists because of the autorelease.

I don't know how your variable definition is in your class but the rule is that in your getter you should return the object unchanged for the reference count. It's the responsability of the caller to call retain if it want to keep a reference on it.
- (NSString*) name {
return name;
}
// caller
NSString* name = object.name;
[name retain]; // if necessary. If the string is used only in the context of a method you do not have to retain it.
If you are using the returned value as a field in another class you should define your field like this:
#property(retain, nonatomic) NSString* name;
With this a retain will be called when you assign to the variable.

No, this is fine. autorelease will cause the value to be released when the current autorelease pool is drained.
Every retain must be matched with exactly 1 of either release or autorelease.
However, I believe both the retain and autorelease are unneeded here. Generally you want to use that autorelease idiom because you've alloc'ed something in the method.

No. The autorelease will balance it out. I don't think, however, that the retain and autorelease would be necessary. You can simply use return name.

As others have said, you do not need to retain or autorelease the property. Since callers of the 'getter' method did not create the object, they do not own it, and you are safe to assume that they won't tinker around with its retain count.
But, callers could potentially change the value of the variable returned by the getter, which would affect the object. Therefore, it would probably be a better idea to return a copy of your variable, especially since it is an NSString. (Getters for NSString objects often return a copy.)
- (NSString *)name {
return [[name copy] autorelease];
}
In this scenario, you are creating a copy of the variable, so you 'own' it. By autoreleasing it before it is returned, you ensure that it will survive long enough to be used in the caller's scope, and that any changes they make to the 'name' variable will not affect the underlying object.

I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
No, because you are already releasing it. autorelease just means “send yourself release later”.
I think you should review the memory-management rules.

I think I might have figured it out:
if [myString] is created outside the method then your safe to use ...
return myString;
if on the other hand [myString] is created inside the method and therefore needs to be released and returned, then you use.
myString = [[NSString alloc] initWithFormat: #"Send me home"];
return [myString autorelease];
This way the method sets [myString] to autorelease, Basically the object is created, set to autorelease and returned. The object will ultimately be released when the pool is destroyed.

Related

Basic memory management confusion

I bet that I could find the answer of this question from reading similar threads here or by googling, but I would like "hear" it first hand so to speak because it's an anomaly in my understanding.
So here's the thing, I have some code which a previous employee wrote and I see a lot of a certain type of construct which looks rather odd to me and I just want to clarify what is "right and wrong".
For example
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
Here wwanServiceIdis a NSString member of the class, and to me this seem like a strange way to do it. As far as I understand it would begin by putting an autorelease on the object, basically saying: "whenever this object seem to not be used, release it for me I don't really care" then the copy will up the retain count +1 on.... wwanServiceId? or newValue? I guess the first.
Then to make me all more confused let's just quickly run through the life-cycle of the wwanServiceId-string..
basically the value will be set if we receive a notification which then from the notification-handler method will call the above -setWwanServiceId: method. other than that it will only ever be accessed for reading, so we are safe to say that it will at any given point:
put autorelease on object
retain a new string copy
Then there is one more quirk to this and this is where I am getting rather suspicious, namely in the -dealloc method which looks like this:
- (void) dealloc {
[[self wwanServiceId] release];
[super dealloc];
}
So what happens there? it will afaik release the wwanServiceId and as I said the only time it's memory management is being touched (if I haven't missed anything but I feel pretty sure) is to put an autorelease and retain it.
So to summarize:
Is the idea here that he thought that since he always retain a new copy after putting autorelease he need to release it in the end.. or well it's the only thing I can think about. Or just felt it would be safe to do an extra release in the end just in case..?
Because as far as I understand it, if this setter is called one time it will put an autorelease (-1 in future), do a retain (+1) and when destructor is called it will do the "final release" (-1).
Any ideas or suggestions helping me understand (if in fact I am wrong and the memory handling is correct as is) would be appreciated.
You wrote:
Here wwanServiceIdis a NSString member of the class, and to me this seem like a strange way to do it. As far as I understand it would begin by putting an autorelease on the object, basically saying: "whenever this object seem to not be used, release it for me I don't really care" then the copy will up the retain count +1 on.... wwanServiceId? or newValue? I guess the first.
This seems to point to the source of your confusion. wwanServiceId is a variable which can contain a reference to an object of type NSString. Variables do not have reference counts only objects do.
The previous employee wrote:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
The expression [wwanServiceId autorelease] means: read the reference stored in wwanServiceId and autorelease the object that reference refers to - let's call that object A. Important: This does not delete object A; it will be released as some later stage and if at that time there are no remaining references object A will be deleted.
The expression [newValue copy] means: read the reference stored in newValue, use that to locate the object (call it object B), make a copy of that object to produce a new object (call it object C), and return a reference to the new object. This new object is owned by the caller of copy, so there is no need to retain it.
Finally the assignment stores the reference to object C into wwanServiceId.
So there is a maximum of three distinct objects involved:
A: the original object referenced by wwanServiceId, this is autoreleased to remove the ownership of wwanServiceId.
B: the object referenced by newValue, this is left untouched
C: a newly created copy of B owned through wwanServiceId
Why "autorelease" in the code and "maximum of three distinct" above?
The method could be called with newValue referencing object A, e.g. as in:
[self setWwanServiceId:[self wwanServiceId]]
If this was to occur and (a) release was used instead of autorelease and (b) there was no other reference to object A then the release would delete object A and then when [newValue copy] was evaluated newValue would be referencing a deleted object... The use of autorelease in this case delays the deletion until after the copy.
So what the previous employee wrote is not in any way "wrong", but as some of the other answer suggest it may be an unusual style. Another way you see this written is:
- (void) setWwanServiceId: (NSString *) newValue
{
NSString *oldValue = wwanServiceId;
wwanServiceId = [newValue copy];
[oldValue release];
}
which also ensures any deletion occurs after the copy.
HTH.
To be short and helpful:
This is wrong:
- (void) setWwanServiceId: (NSString *) newValue {
[wwanServiceId autorelease];
wwanServiceId = [newValue copy];
}
This is right:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
To explain in short:
[wwanServiceId autorelease]; is an unnecessary sent message, because autoreleasing an object will reduce the retain count at some unknown point in the future. And in the next line you are wwanServiceId = [newValue copy]; instantly setting the instance variable. So, in your memory you now have a to be autoreleased object and a new object. One of them is too much The new object is, where the pointer of your IVar is pointing to. The old one is swimming in your Memory Pool with probably no reference to it :-)
Autorelease as few as possible or use ARC.
Oh: And in the dealloc method, please do not send the message like this:
[[self wwanServiceId] release];
Better like this:
[wwanServiceId release];
as Apple recommends to work directly with instance methods in init and dealloc methods, instead of using getters and setters there.
Debug it and have a look.
[wwanServiceId autorelease];
wwanServiceId has an address. This statement does not change it. It does decrement the retain count of this object though.
Thats it.
wwanServiceId = [newValue copy];
This statement creates a new object. The new object is a copy of newValue. Compare the addresses of the objects and you will see, that the address inn wwanServiceId will vary from the address of newValue and it will vary from the address that wwanServiceId did have just before the statement was executed.
The retain, that is implicit in copy will affect wwanServiceId, but it affects the new object, that was just creaed with copy. It does not affect the wwanServiceId object which was autoreleased during the statement before.
At some point after the execution of setWwanServiceId had finished, the old and autoreleased object will dissappear. (Assuming that the retain count is 0 now. If it is >0 because it is still retained for other reasons or just for error, then it will remain and potentially cause a leak.)
Once you understood that you will not question any more what is happening in the dealloc method. wwanServiceId is released. Meaning its retain count is reduced by 1. In the event that it is 0 then it will be deallocated automatically.
You could even autorelease it there too. The diffrerence to autorelease is basically that an autoreleased object is still around and available while the current method is being executed. Its release comes into effect at some later point in time.
But there is no reason for autoreleasing the object in dealloc.
In the example given there is not even a good reason to autorelease the object in the setter setWwanServiceId. You may well release the object directly in both methods.
Assuming wwanServiceId is the private ivar mapped by the getter wwanServiceId and setter setWwanServiceId, I think it is not correct to autorelease the ivar in the setter.
I would have coded the following:
- (void) setWwanServiceId: (NSString *) newValue {
if (newValue != wwanServiceId) {
[wwanServiceId release];
wwanServiceId = [newValue copy];
}
}
What I mean is: it is not necessary to give ownership of your var to the autorelease pool (which it may be drained at the end of the application). Simply release the ivar. If someone is using it, no problem, it will have a strong reference to it. Otherwise it will be deallocated.

Objective-C .mm in initializer and class factory method

This is a question related to Objective-C memory management.
On the About Memory Management page there are some examples
- (NSString *)fullName {
NSString *string = [[[NSString alloc] initWithFormat:#"%# %#",
self.firstName, self.lastName] autorelease];
return string;
}
and the second one
- (NSString *)fullName {
NSString *string = [NSString stringWithFormat:#"%# %#",
self.firstName, self.lastName];
return string;
}
The only difference is that in the first example an initializer is called, and in the second a class factory method.
Basic memory management rules section is said that after an alloc call I will own the object I allocated. So in the first example I allocate an object and at the same time initialize it. In this I own the object and have to release it. In the second example I don’t. But doesn’t the factory method stringWithFormat: do the same thing in one call, I mean allocating the object and initializing it?
So the main question is, why don’t I have to release the object in the second example?
are there any special memory management rules when implementing a class factory method?
By convention, a class factory method will return an object that is in the autorelease pool. It has done the alloc, init, autorelease for you, just like in the first example. Unless you retain it, when the pool is drained, it will be released.
In the second example, you didn't create the string. You only create objects by invoking methods that begin with alloc, new, copy, or mutableCopy.
You may take ownership, if you like, by invoking retain, but then you're also responsible for invoking release. In this example, there's no need. You don't need the string any more. What the caller does with it is their responsibility.
When invoking a factory method like this, you typically receive an autoreleased object. But you don't really need to think about that. Because you didn't create it (because you didn't use a method beginning with alloc, new, copy, or mutableCopy to get that string), all you need to do is think about the retain count delta -- do you need to retain it to keep it from disappearing from underneath you. Since it's just being returned to the caller, the answer in this example is no.
You are right, the factory method internally calls the alloc, and thus returns retained object, but it adds that object to the nearest autorelease pool, so when that pool will be drained, the object will be released.

Returning autoreleased objects using ARC

Assuming that I wrote the code below in a class A:
-(NSArray *) returnListNames {
NSArray *returnList = [NSArray arrayWithArray:myListNames];
return (returnList);
}
And in a class B I get that list in some scope in this way:
{
/* Without ARC I would retain the array returned from ClassA
to guarantee its reference like this:
[[myClassA returnListNames] retain]; */
NSArray *myNames = [myClassA returnListNames];
}
Considering that the returnList was allocated using an autorelease method, how can I guarantee that I won't lose the reference to it using ARC (under which I can't use retain)?
Will I have to use [[NSArray alloc] init] on the myNames array? Or I must use alloc on returnList instead of an autorelease method? Or can I just rely on ARC? Or is there another solution?
ARC will handle this for you, so you can just rely on it and go about your business with that array. If it sees that you need to retain myNames, it will add a retain call for you for example, or do whatever else it actually does when you compile the code that uses it.

Objective C Memory Management Woes

I know this has been discussed ad-nauseum but I just don't get some of the memory management. I understand that retain keeps the object alive and copy gives one a separate copy of an object.
What I don't get is when it comes to ivars & properties, retain as a property means that the setter releases the old value & retains the new:
property = newValue;
// retain
if (property != newValue)
{
[property release];
property = [newValue retain];
}
but I've seen examples where they assign static strings to the retain property ivars e.g.
self.stringProperty = #"something";
(some other code)
self.stringProperty = #"somethingElse";
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
Also, if an object is declared with the retain property & then is assigned something with init, e.g.
#property(retain)someArray;
someArray = [[NSArray alloc] initWithArray:arbArray];
does that mean someArray now has a retain count of 2 but if it was created with
someArray = [NSArray arrayWithArray:arbArray];
the retain count is only 1 because the 2nd is a factory method?
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
You can pass release to a constant string, it just won't do anything meaningful, so those lines of code are valid.
does that mean someArray now has a retain count of 2 but if it was created with...the retain count is only 1 because the 2nd is a factory method?
Well, first of all,
someArray = [[NSArray alloc] initWithArray:arbArray];
doesn't use the methods created by #property, it just accesses the ivar directly. To use the property methods, you'd have to use self.someArray = ...;.
But yes,
[[NSArray alloc] initWithArray:arbArray]
returns an object with an effective retain count of 1, and
[NSArray arrayWithArray:arbArray]
returns an object with an effective retain count of 0, so if you did pass them through the "retain" setter created by #property, the ivar would have an effective retain count of 2 and 1, respectively.
This is more that one question, but anyway...
Static strings are special cases in a number of ways, one of which is that you can retain and release them to your heart's content without it having any effect.
As an aside, NString properties often have copy rather than retain semantics, which would anyway obviate that question if it mattered. But it doesn't.
In your second case, assigning to a retain property directly from an alloc (or copy or other ownership-granting call) is bad practice and will leak unless you actively add a corresponding release afterwards, or autorelease during, eg:
self.someArray = [[[NSArray alloc] initWithArray:arbArray] autorelease];
But there's really no reason not to use the class method in this particular case.
The second call to set string should call release on the static string which is not allowed, why doesn't the program crash?
It's not a static string, it's a constant string. However, that is irrelevant to the question, but actually you are allowed to send -retain to any Objective-C object derived from NSObject except NSAutoreleasePool. If you look at the retainCount (a bit naughty, but since we are discussing implementation, OK) of a constant NSString e.g.
NSLog(#"retain count = %u", [#"foo" retainCount]);
you'll most likely find it's set to a really big number (UINT_MAX in fact). This is a signal to the run time to ignore calls to release and retain.
By the way, forgetting to release objects won't crash the program straight away. In fact, if you have lots of RAM, you might not notice until the OS starts swapping.
does that mean someArray now has a retain count of 2 but if it was created with
No, because you didn't use the property to assign the new array, you went straight to the ivar:
self.someArray = [[NSArray alloc] initWithArray:arbArray];
would be a leak.
self.someArray = [NSArray arrayWithArray:arbArray];
would be OK.

Object ownership in stringWithString and initWithString in NSString

I understand that any init... method initializes a new object and that NSString stringWithString makes a copy of the parameter string as a new object. I also understand that being the objects' owner, I can control the release/deallocation of any objects that I allocate. What I don't understand is when would I use the stringWithString method since any local variable assigned that way would have it's memory "owned" by NSString instead of the local class.
The "Programming in Objective C" book by Kochan (1st ed) uses the following code (see pages 342-344) to explain that the initWithString is preferable to stringWithString because the AddressCard class would own the name variable contents. Also, I don't get any errors making repeated calls to the setName version with the stringWithString method. TIA!!
//header file has appropriate declarations but not included here:
#import "AddressCard.h"
#implementation AddressCard;
-(NSString *) name
{
return name;
}
//Recommended code:
-(void) setName: (NSString *) theName
{
[name release]
name = [[NSString alloc] initWthString: theName];
}
//Incorrect code according to Kochan:
-(void) setName: (NSString *) theName
{
[name release]
name = [NSString stringWthString: theName];
}
//rest of class implementation code snipped
#end
What I don't understand is when would I use the stringWithString method since any local variable assigned that way would have it's memory "owned" by NSString instead of the local class.
What? No.
The rules are simple:
Any object returned by alloc, copy, copyWithZone, or new has a retain count of 1.
retain increases the receiving object's retain count.
release decreases the receiving object's retain count.
autorelease tells the current autorelease pool to send the receiving object the release message “later”.
Any factory method that doesn't have “new” or “copy” in the name (e.g., stringWithString:) returns an object that it has autoreleased on your behalf.
Or, digested a bit:
Any method whose name contains copy, alloc, retain, or new returns an object that you own.
Any method that doesn't, returns an object that you don't own.
To own an object, retain it.
The incorrect implementation of setName: that you show is incorrect because it stores an autoreleased object in an instance variable, when you mean to own the object. You should retain it or, in this case, copy it. One way is to simply use alloc and initWithString:, as in the correct example you show; the other way would be copy.
The Memory Management Programming Guide for Cocoa explains everything. Every Cocoa or Cocoa Touch programmer should read or re-read it from time to time.
Actually, both setters are wrong. The 'incorrect' one is wrong for general memory management reasons (which are well-expounded elsewhere). The 'recommended' one is wrong for 2 reasons:
if (theName == name), then you're
likely to deallocate your object in
the first line, and then attempt to
use the deallocated object as a
parameter to -initWithString: on the
second line, resulting in undefined
behavior.
-initWithString: does not handle being passed nil gracefully.
The 'correct' (IMHO) method is:
-(void) setName: (NSString *) theName
{
if (theName == name) return; // if they're equal, no need to do anything further
[name release];
name = [theName copy]; // sets name to nil if theName is nil
}
For most objects you'll actually want to -retain instead of -copy on that third line, but for strings it's almost always better to copy.
The difference between initWithString and stringWithString is that stringWithString returns an auto-released pointer. This means that you don't need to release it specifically, since that will be taken care of next time that the auto-release pool cleans up any auto-released pointers.
initWithString, on the other hand, returns a pointer with a retain count of 1 - you do need to call release on that pointer, or else it would result in a memory leak.
See https://stackoverflow.com/questions/193288/what-is-the-cost-of-using-autorelease-in-cocoa for some reasons as why you should use auto-release vs release.
In the Incorrect code above, the next time name is referenced after setName is called, you'll get an exception error, since the object will have been released. You can use either the "Correct" code, or wrap your stringWithString call in an explicit retain call:
name = [[NSString stringWithString: theName] retain];
What I don't understand is when would I use the stringWithString method since any local variable assigned that way would have it's memory "owned" by NSString instead of the local class.
A string created with stringWithString: isn't owned by the NSString, it is owned by the NSAutoreleasePool (although multiple places can retain an object, making ownership shared).
With stringWithString:, the string will become invalid when the autorelease pool is next processed (normally during the application's next event loop) because the NSAutoreleasePool will release its pointer. If you have not retained the string before then, any pointer you have to it (name in the case of your class) will be invalid (the variable name will still exist but it will point to garbage).
Autorelease is good, if you don't intend to keep any pointers to the NSString but since you do intend to keep a pointer, you'll need to retain the NSString. initWithString: gives you a retain count of 1 automatically.