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...
Related
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.
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/.
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.
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.
In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.
What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?
Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?
I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.
Thanks for your help.
Your autorelease is correct in the return just retain it when you call the static method.
NSArray *data = [[StaticClass getArray] retain];
If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.
Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.
It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.
If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.
Regards your comment to Matt's answer. Your code is this:
for (NSString * date in dateList)
{
[historyList addObject:[[BIUtility historyForDate:date] retain]];
}
and
+ (NSArray *) historyForDate:(NSString *)date
{
NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];
}
The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.
By the way, historyForDate: does nothing with the date. Is that correct?