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!!

5 Answers
5

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.

So, this means if I retain any object then I need to release it. In other words; if I alloc the object then I need release it anyway, but if I retain it before release once. How many times do I need to release?
–
Mohammad AbdurraafayMar 5 '11 at 16:12

@Mohammad Abdurraafay: If you alloc it and then retain it, you own it twice, so you need to release it twice.
–
Peter HoseyMar 5 '11 at 17:12

my question is, if I make a copy of the argument by alloc and initWithString (then I own it), and thus I should override the dealloc method and release it myself?
–
shiying yuOct 6 '11 at 8:39

@shiyingyu: That's correct. The same is true if you make a copy of the argument by sending it copy. Either way, you own the copy and must release it.
–
Peter HoseyOct 6 '11 at 14:50

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.

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.

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:

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.