The common practice in IOS setters is the following:
- (void)setMyString:(NSString *)newString {
if ( newString != myString ) {
[myString release];
myString = [newString retain];
}
}
On the contrary this is not good practice
- (void)setMyString:(NSString *)newString {
if ( myString != nil ) [myString release];
myString = [newString retain];
}
}
What is the reason checking for equality in the first case? What is the problem in the seconds case?
If you set something like this [object setMyString:[object myString]]; without checking for equality - it will be crash! Because it will be released before you send it message retain. (in case when only object own string). Also in first example we checking for equality to avoid extra operations.
I know this is somewhat redundant, but...
If the new and old object are the same then you send release to the old object and it gets deallocated, the pointer to the new object will become a dangling pointer as the object it pointed to will no longer exist (since it pointed to the same object as the old object pointer). Ex. if myString and newString point to the same instance who has a retain count of one, then you subtract one, it'll equal zero. it's too late to add one now, because it'll get deallocated. However, reverse the calls to retain and release and it should be fine. If the retain count is one and you add one, it's now two, and you can safely send release. In general, I'd say before you disown an object, assert ownership of the new one first.
Also, the first type of setter would be what you would use for retain/strong style setter. If it were assign you wouldn't need to retain/release as no ownership is supposed to be asserted. NSStrings often have a copy style setter which copies the argument and uses that, which would create a copy instead of retaining. I would generally use copy for anything with a mutable subclass as you wouldn't want someone passing in a NSMutableString and mutating it behind your back. This page goes into accessors, and you'll notice that they retain the new value before releasing the old one, and explain why.
You may take this to though the memory management, https://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/.
Related
In MRC code returning NSArray element like this:
NSString* MyName()
{
NSArray *names = [NSArray arrayWithArray:[[NSHost currentHost] names]];
return [names objectAtIndex:0];
}
void BullCrap()
{
NSString *wouldItBeRetainedAutomatically = MyName();
}
wouldItBeRetainedAutomatically in BullCrap() scope? I am assuming I don't need to send wouldItBeRetainedAutomatically retain message to make sure it is still available after names in MyName() is deallocated? Or names wouldn't be deallocated until BullCrap() is done?
NOTE: I know I should use ARC, but i can't.
In order to be completely sure the answer to this question is correct it would be necessary to see where listOfNames comes from. This will tell us what memory management contract has been made between the system framework and your calling code.
With that said, it is probably safe to say that the system framework has autoreleased the NSArray that was returned and stored in listOfNames. So listOfNames will get released and disappear as soon as the autorelease pool is flushed. You create the name array using arrayWithArray which will also return an autoreleased instance.
However, you are specifically asking about the memory management "state" of the first element of listOfNames (or names) that is returned by the MyName function. This has almost certainly only been retained by the listOfNames array (and the names array). (Again the caveat above still stands). Given that listOfNames (and names) will get autoreleased shortly, the elements of the array will also get released.
Therefore, you should probably return the element from MyName with a call to autorelease and then retain wouldItBeRetainedAutomatically in BullCrap if you need it to stick around. There is nothing in the code that you've shown that would suggest it will be retained automatically for you.
On a side note, the names array that you create is unnecessary in the example you give. The same could be achieved as follows:
NSString* MyName()
{
//listOfNames is returned by SystemFramework API
return [listOfNames objectAtIndex:0];
}
Using the intermediate names array simply confuses the matter.
In this case it looks like you shouldn't do anything, simply because you say listOfNames is returned by a system API and this method is (in a very contrived way) adding it to and then removing it from an array which will be destroyed. So, the array temporarily retains the listOfNames but doesn't really change anything and the listOfNames is (depending on how it was really created) already auto released.
Obviously there's a massive caveat on where listOfNames actually comes from...
I would like some help better understanding the memory characteristics of Strings in Cocoa.
The app I am working with uses one view controller and n tool objects. The View controller lives for the life of the program but the tool objects are allocated and released.
Suppose I have a string toolName_ and in my implementation I configure the incoming tool object: if the object does not have a tool name, I want to set the toolName_ string to #"not set". If the tool has a name I want to set the string to the name of the tool.
I would like to know the proper way to store the incoming value into the toolName_ given that sometimes this will be an allocated object and sometimes this will be a constant string.
-(BOOL)setToolObject: ToolObject: obj{
ToolObject someObj = nil;
someObj = [[ToolObject alloc]initWithObject obj];
if(someObj != nil){
if(! [someObj.toolName isEqualToString: #""]){
self->toolName_ = Which method should I use given the above question?
The last instance may have been a constant string but may not have.
[self->toolName_ release] (can I send a release message to a constant
string without causing a problem?)
self->toolName = [[NSString alloc]initWithString:someObj.toolName];
OR
self->tool name = [NSString stringWithString: someObj.toolName];
This method is self releasing but I don't own it and I'm still not sure
what happens to the constant string if it existed. I think I read it's
not recommended to use this on member vars.
}else{
self->toolName_ = #"not set";
}
return YES;
}else{
return NO;
}
}
Advice appreciated.
I highly suggest to (possibly) use ARC, and if you can't use it (or maybe you just want to understand how memory management works?), to don't send retain and release messages from outside the class. Instead you should do this in the accessors.
So you should create a retain or copy property (usually with immutable strings is preferable to use copy, because they may be assigned to mutable strings, so making invalid the assumption that you are working with an immutable - thus thread safe - property).
So in your case I suggest a setter like this one:
- (void) setToolName: (NSString*) toolName
{
if(_toolName== toolName)
return;
[_toolName release];
_toolName= [toolName copy];
}
This way you're doing it fine, you shouldn't be concerned about what is the retain count of the setter argument. In case it is a string literal which has an unknown retain count, the object does not even respond to a release message, so it will stay alive for all the program (unlike it seems it is efficient because it avoids the overhead of creating an object at runtime). If you copy an immutable object (unless it something like a cached NSNumber, or a string literal), the code just does a simple assignment and the retain count gets increased.
So if you just follow the rule of "I retain (or copy) what I need to use, I release what I don't need to use anymore", you're doing it fine and you shouldn't worry about what happens in particular case like with string literals.
NSArray *array = [dictionary objectForKey:#"field"];
and
NSArray *array = [[NSArray alloc] initWithArray:[dictionary objectForKey:#"field"]];
I see both kind of approaches very frequently in objective C code.
When tried to understand, I found both of them used in similar situation too, which makes contradiction. I am not clear on when I should use 1st approach and when 2nd one?
Any idea?
Detailed explanation and useful references are moms welcome.
First off, those two examples are doing slightly different things. One is retrieving something from an existing dictionary and one is creating a new array by retrieving something from an existing dictionary (the value of that key is an array).
But, if you're asking the difference between getting objects by alloc vs. convenience methods. ([NSString alloc] init vs [NSString stringWith ...), by convention, you own anything that you call alloc, new copy or mutableCopy on. Anything that you call that is not those, is autoreleased.
See the memory guide here. Specifically, look at the rules.
Getting an autoreleased object means it will go away at some point in the near future. If you don't need to hold onto outside the scope of that function, then you can call autorelease on it or use one of the convenience methods that's not alloc, etc...
For example:
// my object doesn't need that formatted string - create the autoreleased version of it.
- (NSString) description {
return [NSString stringWithFormat:#"%# : %d", _title, _id];
}
// my object stuffed it away in an iVar - I need the retained version of it. release in dealloc
- (void) prepare {
_myVal = [[NSString alloc] initWithFormat:"string I need for %d", _id];
}
In the first example, I created a convenience methods for others to call, my class doesn't need that object beyond the scope of that method so I create the autoreleased version of it and return it. If the caller needs it beyond the scope of his calling method, he can retain it. If not he can use it and let it go away. Very little code.
In the second example, I'm formatting a string and assigning it to an iVar variable that I need to hold onto for the lifetime of my class so I call alloc which will retain it. I own it and releasing it eventually. Now, I could have used the first version here and just called retain on it as well.
You have a fundamental misunderstanding of allocations versus instance methods.
The first example, NSDictionary's -objectForKey method, returns id, not an instance of NSDictionary, therefore it does not allocate or initialize the variable.
The second, however is the classic retain part of the retain-release cycle.
The two methods are fundamentally equal (if we are to assume that array is alloc'd but empty in the first, and nil in the second), and both get ownership of the array object. I would go with the second, as it guarantees a reference, and it's shorter.
What I think you're confusing this with are new and convenience methods. Convenience methods (like NSNumber's +numberWithInt:, NSString's +stringWithFormat:, and NSMutableArray's +array), return an autorelease instance of the class (usually). New takes the place of alloc and init in just one word.
I am new to Objective-C, so this might be a dumb question.
I cannot help but see the similarities between ObjC and Microsoft's COM with respect to memory management (AddRef/Release vs retain/release). In a COM environment, it's more or less imposed on you to always AddRef (retain) an object before returning it to the caller. From what I've seen so far (I'm a third through Cocoa® Programming for Mac® OS X (3rd Edition)), the memory management part is somewhat fuzzy.
Assuming there is no GC, what is the idiomatic way to return an object?
Read Memory Management Programming Guide about autorelease pools.
In Objective-C, by convention, objects should be returned autoreleased (unless the method returning the object has a name that begins with “alloc”, “new”, “copy”, or “mutableCopy”). Autoreleased objects are tracked by Objective-C in a pool and automatically handled, which means you don't need to care about sending a final release to them. This greatly simplifies reference counting compared to COM, and this is why you're not seeing any release calls on returned objects most of the time. In contrast, the same convention specifies that all objects returned by a method whose name begins with alloc, new, copy, or mutableCopy, are the responsibility of the method caller. You have to manually call release on these objects or your program will have memory leaks.
Cocoa goes around the limitations of AddRef/Release in COM by introducing a third sibling; autorelease.
retain - I need this, make it stick around.
release - I don't need this anymore, you may remove it immediately.
autorelease - I don't need this, but let it stay around a few seconds in case someone else wants to pick it up first.
This tiny addition allow most return values to be handles as-if we had garbage collection. If you are not interested in keeping the return value around, just do nothing extra.
In order to get this to work there is a convention (a convention good enough to let the compiler do the memory stuff automatically for you with upcoming ARC):
Method names beginning with these must return retained instances:
alloc
copy
new
retain
All other must return autoreleased instances.
Three example implementation for how this can be applied in practice:
-(NSString*)newHelloWorldString {
NSString* s = [NSString stringWithString:#"Hello world"];
// Apply retain because s in now autoreleased
return [s retain];
}
-(NSString*)helloWorldString {
NSString* s = [[NSString alloc] initWithString:#"Hello world"];
// Apply autorelease because s is now retained.
return [s autorelease];
}
-(NSString*)fullName {
// No memory management needed, everything is autoreleased and good.
NSString* fn = [self firstName];
NSString* ln = [self lastName];
NSString* s = [NSString stringWithFormat:#"%# %#", fn, ln];
return s;
}
Generally something like
return [object autorelease];
and you can retain on the other end.
If you are planning to deploy on Lion/iOS5 or are using the latest SDK then also check out ARC.
Essentially i would recommend making the class that receives it retain it. i.e class stackoverflow receives object answer.
i.e
-(void) setAnswer:(Answer*) _answer{
self.answer = _answer; // If the answer is created from a returned message.
[_answer release];
}
edit: I think I might have put up the wrong stuff up there now that i am looking at it the 2nd time . Meant something along the lines:
Answer *_answer = [stackoverflow createAnswer];
self.answer = _answer;
[_answer release];
If you return an object , it is up to the owner to retain it , i would avoid autoreleases wherever possible because once the nspool kicks in, those objects are gone and if they are still used, it will cause problems.
i.e Answer *answer = [stackoverflow getAnswer] and if answer was created in the getanswer method then whomever is retrieving it is responsible in releasing it.
Makes sense?
In the following function which one is the best practice?
To send an autoreleased object, and make the caller retain it?
or send an allocated object, and make the caller release it?
- (NSString*) convertDataToString :(NSData*)myData
{
//just an example, method might not exist
NSString *str = [[NSString alloc] initWithData:myData];
return str;
return [str autoRelease];
}
Following up on #Chuck's comment, -convertDataToString must not return an object that the caller must release. That would violate the Three Magic Words. If you do not have "copy," "alloc," or "new" in your name, the caller cannot be expected to release the object. If you have "copy" in your name or start with "new" or "alloc," then the caller must release the object.
Objective-C relies heavily on consistent naming and the names mean things. If you learn the naming, then you won't have any problems.
The memory management rules say your first example is — and this is a direct quote — wrong. It's not even a matter of preference, as some answers here seem to indicate. The caller does not normally own the object you return, so it should be autoreleased.
The specific example from the rules says this:
This is wrong. Following the ownership policy, it would result in a memory leak.
– (NSArray *)sprockets {
NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,
auxiliarySprocket, nil];
return array;
}
The object’s reference to the new array object is limited to the sprockets method. After the method returns, the object loses its reference to the new object so cannot relinquish ownership. That in itself is not a problem. However, following the naming convention set out earlier, the caller is given no indication that it owns the returned object. The caller would therefore not relinquish ownership of the returned object, leading to a memory leak.
You'd want to return an autoreleased object most of the time.
Unless your method name contains one of the following words [alloc, new, copy], you should return an autoreleased object.
If you create, alloc, or copy an object, you are responsible for releasing it. Based on this, you should return an autoreleased object.
I prefer to return the autorelease. It means that you aren't hunting around trying to find where memory is being freed. Keeping memory allocation and deallocation together makes your life easier. After all, you're coding this, why make it harder on yourself.
Both are acceptable, but you should name your method accordingly : if the caller has the responsibility to deallocate it, you have to make this explicit by having your method name contain "create", "alloc" or "copy", else it should not.
More reading on this at http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH
It might be a bit more customary to return an autorelease object, but both are okay.