How to assign a string value in Objective C using ARC? - objective-c

Using ARC, is it now OK to assign a string value like this:
self.userName = [[NSString alloc] initWithString:self.currentParsedCharacterData];
Or does that still cause a memory leak, thus requiring me to assign it like this:
NSString *tmpString = [[NSString alloc] initWithString:self.currentParsedCharacterData];
self.userName = tmpString;

The first snippet is just fine under ARC, and is the better of the two ways. Apple has an example like this in the Transitioning to ARC guide:
- (void)contrived {
Person *aPerson = [[Person alloc] init];
[aPerson setFirstName:#"William"];
[aPerson setLastName:#"Dudney"];
[aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]];
NSLog(#"aPerson: %#", aPerson);
}
and says:
ARC takes care of memory management so that neither the Person nor the NSNumber objects are leaked.
The setYearOfBirth: message with an alloced NSNumber corresponds to your snippet.
The compiler understands that, in the first case, aPerson is going out of scope and needs to be released before that happens, and, in the second case, that there is no explicit reference to the NSNumber object and that it must be either released or put into the autorelease pool. It takes care of both these requirements on your behalf.

Yes, with ARC it is ok. In fact, I would recommend the first way you have it implemented.

Either of your examples is fine. There is no difference between the two as far as memory management/ARC goes.

Related

__weak reference is still a mystery for me

NSString *myString = [NSString stringWithFormat:#"string1"];
__weak NSString *myString1 = myString;
myString= nil;
NSLog(#"%#, %#",myString,myString1);
I was expecting null , null. But the output is string1, (null). Why is myString1 still holding the value as myString is set to nil?
Weak references only get zeroed when the object is deallocated. That object is not immediately deallocated (it's probably in an autorelease pool here, though there are many other reasons something might be held onto in different situations), so the reference stays alive.
Try something like this:
NSString *myString;
NSString* __weak myString1;
#autoreleasepool{
myString= [NSString stringWithFormat:#"string1"];
myString1= myString;
myString= nil;
}
NSLog(#"%#, %#",myString,myString1);
Explanation
You probably noticed that there are many methods to allocate a string or generally an object:
1) [NSString stringWithFormat: ...] / [[NSString alloc]initWithFormat: ...] ;
2) [NSArray arrayWithArray: ...] / [[NSArray alloc]initWithArray: ...];
...
(Also for many other classes)
The first category of methods return an autoreleased object. The second one a non autoreleased object. Indeed if in the above code you use alloc + initWithFormat: instead of stringWithFormat: you don't need an autorelease pool to see that both objects will be nil.
I think your question may be answered by this quote from the Memory Management Guide
In particular, you should not design classes so that dealloc will be
invoked when you think it will be invoked. Invocation of dealloc might
be delayed or sidestepped, either because of a bug or because of
application tear-down.
The output should be (null), string1, not string1, (null). I guess you typed it the wrong way around.
You're explicitly setting one reference to nil, but the other reference is still being used within the scope of the definition (because you're using it in the NSLog). So, it won't be released by ARC until that usage is complete.
The weak reference isn't holding onto it. The fact that you're using it means that ARC will hold onto it (by not adding the release code). Once that usage is complete, ARC will release the object and then the weak reference will be nilled.

Playing around with ARC: Force release irritation?

I am currently playing around with ARC a bit to get some things figured out, before starting to do the actual work. I did setup this code:
NSNumber* n = [[NSNumber alloc] initWithInt:3];
__weak NSNumber* weakN = n;
n = nil;
NSLog(#">>>: %# %#", n, weakN);
I expected n and weakN to be nil, as n = nil; should trigger a release in my eyes? Unfortunately it doesn't. The output is ">>>: (null) 3". What am I missing here?
Another thing is, that I am pretty sure, the below code was giving me a hard time when starting with arc:
__weak NSNumber* weakN2 = [[NSNumber alloc] initWithInt:3];
NSLog(#">>>: %#", weakN2);
I am pretty sure, I've had some problems with similar code, as arc would release the object straight after initialization, as there is no strong reference to the object. Unfortunately, the output of the above is ">>>: 3".
It would be great to get some clarification on this stuff. I am clearly missing something here!
Best regards,
Michael
In addition to what kevboh said, it's also rather pointless to create weak references to simple immutable Foundation objects like NSNumber. For performance reasons, Foundation might well vend you a cached object instead of creating an entirely new one. And if it doesn't now, then it might in some future release.
The upshot is that you're probably not the sole owner of the object returned by [[NSNumber alloc] initWithInt:3], no matter what you think.
Well, you just picked a bad object to test this with. If you do it with NSString's (or most other objects), you get the expected result:
NSString* n = [[NSString alloc] initWithFormat:#"3"];
__weak NSString* weakN = n;
n = nil;
NSLog(#">>>: %# %#", n, weakN);
// Output is (null) (null)
__weak NSString* weakN2 = [[NSString alloc] initWithFormat:#"3"];
NSLog(#">>>: %#", weakN2);
// Output is (null)
The behavior of NSNumber is caused because the class is caching the number that was created so is actually still valid. The same behavior will be exhibited if you use string constants that are compiled in as part of the code. (Like NSString* n = #"3";)
I expected n and weakN to be nil, as n = nil; should trigger a release in my eyes? Unfortunately it doesn't. The output is ">>>: (null) 3". What am I missing here?
ARC doesn't work like that. Ownership of the object is nondeterministic; ARC likely held on to it until the end of your function. You should not expect deallocs to happen and instead use strong/weak references when you intend ownership to happen.

Is this a correct situation to call release on an object in Objective-C?

I'm new to Objective-C and I am having some difficulty with understanding memory management.
So let's say I have a class and an instance variable of type NSString* that isn't tied to a property. Would this situation leak memory?
myString = [[NSString alloc] init];
//more program stuff
myString = [[NSString alloc] init];
Should I have called [myString release] before I set myString equal to a new object? Will this sort of code leak memory? Do I have to release an object like this every time I have the pointer point to a different object?
First, Apple's Memory Management Programming Guide is a great place to look for examples and instructions about memory management.
Now to your question. When you call myString = [[NSString alloc] init]; you are reassigning the pointer myString and as such lose access to the original NSString, thus creating a memory leak.
The general rule of thumb here is that for every alloc you should have a release and these must alternate appropriately. If you do
myString = [[NSString alloc] init];
// ...
myString = [[NSString alloc] init];
// ...
[myString release];
[myString release];
you are releasing the same instance twice which results in overreleasing and an error BAD-ACCESS. The correct thing to do is
myString = [[NSString alloc] init];
// ...
[myString release];
myString = [[NSString alloc] init];
// ...
[myString release];
so that each instance is correctly released.
For future, stick to the simple rule that for every alloc/copy/retain you should pair it with a release.
Yes this will leak.
By allocating and assigning another NSString instance to the same variable myString, you lose reference to the original content of myString and therefore the ability to send it a release message.
Both, the Clang static analyzer and the Leaks instrument should uncover this leak.
Yes, you need to release the first object before you reassign your variable to point to the second object. Otherwise, you lose track of your first object and you leak it because you can't release it. You are responsible for releasing the object because you created it (via alloc) as explained in the Memory Management Rules.
Also, bear in mind that [[NSString alloc] init] is creating an empty and immutable string (NSStrings are immutable meaning that they can not be changed after creation). There is little point in doing this.

Releasing objects returned by method

Ok, I know the answer to this question should be obvious, but I need a little push in the right direction.
I find myself writing a fair number of methods that follow the following pattern:
-(NSThing*)myMethod{
NSThing *thing = [[NSthing alloc] init];
// do some stuff with the thing
return thing;
}
My question is, how do I handle the release of this object? Clearly I can't release it within the method.
usually you would autorelease it
-(NSThing*)myMethod{
NSThing *thing = [[NSthing alloc] init];
// do some stuff with the thing
return [thing autorelease];
}
Autoreleasing is the easy way to get out of this, as newacct said. However, you should take into consideration the "ownership" of the object you're returning.
In Objective-C, the general rule of thumb is that any method with alloc, new, or copy in its name returns an object that is not autoreleased, while other methods (like class methods) pre-autorelease the object to be returned. So these three are not equivalent in terms of autorelease (although the compiler may do some magic and reduce them all to string constants anyway):
// Autoreleased
NSString *string1 = [NSString stringWithString:#"aString"];
NSString *string2 = [[[NSString alloc] initWithString:#"aString"] autorelease];
// NOT autoreleased
NSString *string3 = [[NSString alloc] initWithString:#"aString"];
Your code can take a similar approach, where you consider who owns the object you're returning. In the specific example you provided, the method is the one allocing and initing the object, so in general you're responsible for autoreleaseing [sic] it within your own method. However, if you were to write a method that takes a preexisting object and modifies it in some way, you would not own that object and would not be responsible for autoreleasing the returned object. (Doing so could actually cause problems down the road when the autorelease pool to which the object belongs gets drained.)
See also (thanks to Peter and Quinn in the comments!):
Memory Management Rules

Does [NSMutableDictionary setValue: value forKey: key] retain NSString key?

When adding items to NSMutableDictionary using the setValue:forKey: method (I suppose this generalizes to any NSObject) does the dictionary retain the second parameter, the NSString?
For example:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSString *theString = #"hello";
int i;
for (i=0; i<[theString length]; i++){
NSNumber *myInt = [NSNumber numberWithInt:i];
NSString *character = [NSString stringWithFormat:#"%C",[theString characterAtIndex:i]];
[dict setValue: myInt forKey:character];
}
[dict release];
[pool release];
Clearly, there is no reason to release myInt in the loop, it is retained by dict so it can't be released until the end of the code. But is the same true of character? My thinking is that if NSMutableDictionary stores the string in some other way, then one could create a temporary pool around the loop and release those strings instead of waiting until the release of the dictionary.
I am also curious as to why retainCount of character is 7fffffff as if it is an NSConstantString, I would expect stringWithFormat to return an NSString object which would need retaining, but that doesn't seem to be the case.
It's very common in Cocoa for NSString parameters to be copied instead of retained. That's because you could have just as easily given the dictionary an instance of NSMutableString. Because the string's value could change, NSDictionary makes a copy.
But, regardless of how NSMutableDictionary really operates, you don't have to worry whether character needs to be retained. Once you've passed it to NSMutableDictionary as a parameter, it's really that class's problem to decide how to store the data, unless the documentation specifically tells you that retaining the objects are your responsibility.
I also wouldn't worry too much about the retainCount of any object. Following the retain count of an object too closely can lead you down rabbit holes that just make you spin your wheels.
Finally, I really don't think you need to create your own autorelease pool here. Unless you know with absolute certainty that theString is going to be very long, or you've already observed high memory utilization in Instruments, adding the autorelease pool is an unnecessary optimization.
You don't need to retain character there, the dictionary retains it when you set it as a key and your own code has no need to retain it.
You also don't need to worry about why the retain count isn't what you expect. Maybe the Foundation framework has Flyweight-like instances of a load of single-character NSString instances. In any case if you've got the memory management correct following the guidelines, you'll be OK regardless of what the framework's doing behind the scenes. http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html