As NSString strings are immutable, what is the value of the stringWithString: class method?
I get the utility when used with NSMutableString, I just didn't see the utility with the NSString class.
You might have a NSMutableString (or some home-grown NSString subclass) that you want to duplicate.
NSMutableString *buffer = [NSMutableString string];
// do something with buffer
NSString *immutableStringToKeepAround = [NSString stringWithString:buffer];
Of course, you can also just make a copy:
NSMutableString *buffer = [NSMutableString string];
// do something with buffer
NSString *immutableStringToKeepAround = [[buffer copy] autorelease];
but you own the copy and must release or autorelease it.
As "Andy" points out in #318666, it's related to memory management, quoting:
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.
(Taken from here)
Returns a string created by copying the characters from another given string
[NSString stringWithString:#"some string"]
It is equivalent to
[[[NSString alloc] initWithString:#"some string"] autorelease]
Also, if you have a pointer to an NSString, it may actually be a subclass of NSString like NSMutableString. So, if you want to store the string and be guaranteed that it doesn't change, you should make a copy of it, hence stringWithString exists.
As another use case, if (for whatever reason) you create your own subclass of NSString or NSMutableString, stringWithString: provides a handy way to instantiate it with an instance of either NSString, NSMutableString, or MyCustomString.
I often use +stringWithString: when I need to create an NSMutableString but start it with an initial value. For example:
NSMutableString * output = [NSMutableString stringWithString:#"<ul>"];
for (NSString * item in anArray) {
[output appendFormat:#"<li>%#</li>", item];
}
[output appendString:#"</ul>"];
FYI, now that we are compiling with ARC enabled, you don't have to manually release at all, ARC will insert the release calls during compile time. So how is it still different? stringWithString is still added to the autorelease pool which gets drained sometime in the future (unless you created your own autorelease pool). initWithString will have a release call right before the function ends, so if you didn't retain it somewhere in the method, you can be sure that the string is destroyed by the end of the function call. This gives you a tighter control on the memory management as opposed to using autoreleased objects.
Related
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.
Actually I am working on a project with ARC enabled. I know using alloc and init is taking ownership of the object. I know, If I create a string like this
NSString *myString = [[NSString alloc]initWithFormat:#"Something"];
then I need to release the myString on myself. What If I am using ARC enabled? I cannot release on myself. So will it create a leak? Or should I don't create object like this?
I can create a string like below code too.
NSString *myString = [NSString stringWithFormat:#"Something"];
But which type I need to use exactly for ARC enabled project ? What will happen if I use first type?
If you use ARC, all the necessary release calls will be added for you when you compile. It will not leak.
The difference between
NSString *myString = [[NSString alloc]initWithFormat:#"Something"];
and
NSString *myString = [NSString stringWithFormat:#"Something"];
is that the first one will automatically released after the last reference to myString in that block, while the second one is an autoreleased instance that will only be released at the end of the run loop. It's not a big difference, but if you're using a lot of objects, try to avoid autoreleased ones to keep memory usage low.
ARC takes care of the memory management, so no you don't need to worry about calling release on your myString variable, ARC will do that for you. Also as a suggestion I would recommend using convenience methods to create your object such as
[NSString stringWithFormat:#"Something"];
It's enough to set the string pointer to nil to release it.
You can also do the same things that you would be able to do without ARC, but with the advantage that if you don't explicitly do anything, the ARC will manage (almost) everything for you.
So to release it you set it to nil, let's see what else you could do:
NSString* str= [[NSString alloc]initWithUTF8String: "Hello"];
// here the retain count of str is 1
__unsafe_unretained NSString* string= str;
// again 1 because string is __unsafe_unretained
void* data= (__bridge_retained void*) string;
// data retains the string, so the retain count is to 2
// This is useful in the case that you have to pass an objective-c object
// through a void pointer.You could also say NSString* data= string;
str=nil;
// Here the retain count of str is 1
NSLog(#"%#",(__bridge NSString*)data);
UPDATE
Here's why sometimes you don't notice that an object is released:
NSString* str= [[NSString alloc]initWithString: #"hey"];
__unsafe_unretained NSString* str2=str;
str=nil;
NSLog(#"%#",str2);
In this case str=[[NSString alloc]initWithString: #"hey"] is equal to str=#"hey", with the difference that str is autoreleased and not released.But the compiler optimizes the code in str=#"hello", so if you are inside an autorelease block you won't have any problem, str2 will be printed correctly.
That's why I used initWithUTF8String, to avoid that compiler optimization.
I have been programming in Objective-C for a couple weeks now, and I think its time that I think more about my memory management and so I have a couple scenarios I would like clarification on.
NSString *myString = #"Hello, World";
If I were to on the next line do
NSString *anotherString = myString;
Is it getting copied? or is another string just a pointer to myString? if it's just a pointer how would I make anotherString a copy of myString that has its own memory?
What if I were to
[anotherString release];
What actually gets released, just anotherString, or does myString go away too?
Then if I were to do
anotherString = nil;
Does that actually free up memory and for use or does it still have the space allocated with empty memory? Obviously the pointer can still be used. What does it do to myString?
This will really help me become better at managing the memory properly, instead of just [object release]; randomly and causing crashes.
Thank you VERY MUCH in advance to whoever replies.
When you do:
NSString *myString = #"Hello, World";
NSString *anotherString = myString;
...you're creating a single NSString instance, and two pointers to it. So to answer your questions, no it is not being copied. Yes, anotherString is just a pointer, and so is myString, the actual NSString instance is off in memory-land, at the address that both pointers are now pointing to.
To make a copy of the string, you would do:
NSString *anotherString = [myString copy];
When you do:
[anotherString release];
The NSString instance that anotherString points to is released. Nothing happens to anotherString itself. It continues to point to your now-invalidated object instance. If myString was pointing to the same instance, then yes, this causes myString to "go away" as well.
And if you do:
anotherString = nil;
...then you've caused a memory leak, because you reassigned the pointer without releasing the thing it was pointing at. Except not in this case because #"Hello, World" is a literal value that is loaded onto the stack and is not retained by your code.
In any case, setting anotherString to nil does nothing to your string, it just changes what anotherString points to. Your actual NSString instance is still off in memory-land, completely unaware that you just threw away your reference to it (possible exception: reference counted/garbage collected environments).
And yes, calling [object release] randomly will cause crashes. As a general rule you should only call release on something if:
You called alloc and init... on it.
You called retain on it.
You obtained the object as a result of calling copy on some other object.
Note that these stack, so if you alloc something, retain it, and then copy it, you need to have 3 calls to release, two for the object that you alloc'ed, and one for the copy.
As a side note, you may find it clearer to write your object declarations like:
NSString* myString = #"Hello, World";
NSString* anotherString = myString;
...which makes it more obvious that what you are declaring are pointers to NSString's and not NSString's themselves. Personally I think your original syntax, while commonly used, is also backwards.
This string:
NSString *myString = #"Hello, World";
is created on the stack. It's loaded into memory when the app starts. You don't own the memory backing the object, and therefore shouldn't release it.
If you want to copy a string to the heap (where you can manage the memory), you simply do this:
NSString *anotherString = [myString copy];
Then you're responsible for releasing that object when you're done with it.
[anotherString release];
Setting a pointer to nil just clears the pointer, not the object it's pointing to. It's still in memory.
NSString *anotherString = myString;
--- This is just a pointer assignment
--- You can copy myString using [myString copy]
[anotherString release];
--- You are releasing the owner ship of the anotherString (please read about retain count concept)
anotherString = nil;
--- you are just assigning the pointer to nothing.
I suggest Please read more about memory management apple documents ...
Whenever I need to create a new NSString variable I always alloc and init it. It seems that there are times when you don't want to do this. How do you know when to alloc and init an NSString and when not to?
Whenever I need to create a new NSString variable I always alloc and init it.
No, that doesn't make sense.
The variable exists from the moment the program encounters the point where you declare it:
NSString *myString;
This variable is not an NSString. It is storage for a pointer to an NSString. That's what the * indicates: That this variable holds a pointer.
The NSString object exists only from the moment you create one:
[[NSString alloc] init];
and the pointer to that object is only in the variable from the moment you assign it there:
myString = [[NSString alloc] init];
//Or, initializing the variable in its declaration:
NSString *myString = [[NSString alloc] init];
Thus, if you're going to get a string object from somewhere else (e.g., substringWithRange:), you can skip creating a new, empty one, because you're just going to replace the pointer to the empty string with the pointer to the other one.
Sometimes you do want to create an empty string; for example, if you're going to obtain a bunch of strings one at a time (e.g., from an NSScanner) and want to concatenate some or all of them into one big string, you can create an empty mutable string (using alloc and init) and send it appendString: messages to do the concatenations.
You also need to release any object you create by alloc. This is one of the rules in the Memory Management Programming Guide.
If you want to initialise it to a known value, there is little point in using alloc, you can just use a string literal:
NSString* myStr = #"Some value";
If you want to initialise it with a format or whatever, but don't need it to stick around beyond the current autorelease pool lifetime, it's a bit neater to use the class convenience methods:
NSString* myTempStr = [NSString stringWithFormat:#"%d", myIntVar];
If you need its lifetime to go beyond that, either alloc/init or else add a retain to the previous call. I tend to slightly prefer the latter, but the two are pretty much equivalent. Either way you will need a balancing release later.
Note that, since NSString is not mutable, this sort of thing is not only unnecessary but actively wrong:
// don't do this!
NSString* myStr = [[NSString alloc] initWithString:#""];
myStr = someOtherStr;
since it leaks the initial placeholder value.
It seems that there are times when you don't want to do this.
I can't think of any time when I would want to alloc/init a NSString. Since NSStringgs are immutable, you pretty much always create new strings by one of:
convenience class method e.g.
NSString* foo = [NSString stringWithFormat:...];
literal
NSString* foo = #"literal";
NSString instance method
NSString* foo = [bar uppercaseString];
copy from mutable string
NSString* foo = [mutableBar copy]; // foo needs to be released or autoreleased in this case
I'm guessing that you are referring to using StringWithString or similar instead of initWithString? StringWithString alloc and inits for you under the hood and then returns an autoreleased string.
If you don't need to do any string manipulation other than to have the string, you can use NSString *str = #"string";
In general with iOS, the tighter you manage your memory the better. This means that if you don't need to return a string from a method, you should alloc init and then release it.
If you need to return a string, of course you'll need to return an autoreleased string. I don't think its any more complicated than that.
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