If I declare a pointer variable in this fashion:
NSString *foo;
And then somewhere later in my code do something such as:
foo = #"bar";
Is that ultimately taking my NSString, creating a new copy in memory with an additional string, then deleting my initial string? Would foo be better off as an NSMutableString?
No, foo is variable holding a pointer to an NSString. The assignment foo = #"bar" sets the value stored by the pointer foo to the address of the NSString #"bar". There is no copy made. If foo already pointed to an other NSString instance that was not a string constsant (i.e. like #"bar") and there are no other references to that instance, then you have a memory leak. You would
[foo release];
foo = #"bar";
in that case. You do not need to retain or release string constants like #"bar".
String constants cannot be mutated, so you will get a runtime error if you try to modify the value of a constant string. There's no difference between assigning #"bar" to an NSString* vs an NSMutableString*. Of course, you won't be able to use the mutating methods of the NSMutableString without a runtime error just because you assign the address of #"bar" (an NSString instance) to a variable of type NSMutableString*. If you want to mutate the string, you would do
NSMutableString *mutableFoo = [#"bar" mutableCopy];
In this case, a copy is obviously made and you are responsible for releasing mutableFoo when you're done with it.
No. The #"bar" in your example is a string constant, and should be baked into your code. You don't need to worry about memory allocation / deallocation with this constant.
NSMutableString is more efficient to use when you are doing a lot of little manipulations to a string (appending substrings, etc.) and you don't want to keep allocating autoreleased NSStrings all over the place. I tend to avoid autoreleased strings on the iPhone if I can, due to memory concerns within loops.
Related
So I just got asked this at an interview today and after some googling am still unable to figure out the answer (in fact I couldn't even find any code at all which used the [NSString string] method).
What is the difference between
NSString *someString = [NSString string];
NSString *someString = [[NSString alloc] init];
Now my initial thoughts were that [NSString string] would return an object which would be autoreleased whereas using alloc and init would return an object which has been retained. However it seems that this answer was incorrect.
I've looked at the NSString class reference in the apple docs but all it says is
Returns an empty string.
+ (id)string
Return Value
An empty string.
Could somebody explain to me exactly what the difference between these two are?
Was that your response, and did you ask why your answer was incorrect? I ask because your assumption is mostly correct (at a higher level).
It's not exactly 'retained' when returned from alloc+init, it is an object you hold one reference to, and should balance with a release or autorelease. For the convenience constructor (+[NSString string]), you are returned an object which you hold zero references to, but one which you can expect to live until the current autorelease pool is popped unless you send it an explicit retain (assuming MRC or ARC, since it is tagged iOS).
At the lower level, you could make some guesses, but I wouldn't expect that question in many objc interviews (unless you told them you were mid or senior level). Basically, it is implementation defined, but both forms could return the same static, constant NSString (that may have been what the interviewer was looking for). To illustrate:
#implementation NSString
static NSString * const EmptyNSString = #"";
- (id)init
{
self = [super init];
[self release];
return EmptyNSString;
}
+ (id)string
{
return EmptyNSString;
}
...
Again, that's implementation defined, but an obvious optimization. As well, that optimization makes physically subclassing concrete immutable types (NSString) difficult for mutable variants (NSMutableString) in some cases.
Now my initial thoughts were that [NSString string] would return an object which would be autoreleased
Technically, it’s a placeholder string that is constant, i.e., it lives throughout the entire program execution, never being released. It’s not an autoreleased string. Conceptually, and this is what I’d focus as an interviewer, it’s a string (an empty string) that is not owned by the caller, hence the caller shouldn’t release it.
whereas using alloc and init would return an object which has been retained
Technically, it’s a placeholder string that is constant, i.e., it lives throughout the entire program execution. In fact, it’s the same object as the one above, and it is not retained. Conceptually, and this is what I’d focus as an interviewer, it’s a string (an empty string) that is owned by the caller, hence the caller is responsible for releasing it when it’s not needed any longer.
The correct answer is that
NSString *someString = [NSString string];
gives you an empty string that you do not own and that you must not release (according to the memory management rules)
whereas
NSString *someString = [[NSString alloc] init];
gives you an empty string you do own and that you must release (according to the memory management rules).
Without poking into the implementation, you can't say anything else about those two strings. You can't say that they are autoreleased, because they might not be and you can't say what the retain count will be.
In actual fact, you'll probably get (in both cases) the same pointer to a constant object of some NSString subclass, probably with a retain count of UINT_MAX which is used by the run time as a flag to disable normal retain release behaviour for constant strings. I haven't actually tried the above because nobody except the maintainers of the Objective-C SDK needs to care.
You don't often see
NSString *someString = [NSString string];
because it's the same as
NSString *someString = #"";
which is shorter. It's usually used to create an empty NSMutableString
NSMutableString* s = [NSMutableString string];
The only thing I can imagine is that:
Won't allocate memory since it is not made with alloc. It is a constant (an empty string) made by the system and doesn't need to be released.
You allocate the memory for the NSString yourself which means you have to keep track if the NSString still 'lives' or not when you are done with it, and thus need to release it.
To me, the following code looks like it will create a leak -- I might be wrong about this though:
-(NSString*) myString{
NSString* foo = #"bar";
return foo;
}
My question is:
1) Will is create a memory leak as foo is not released?
2) If it IS a memory leak then how do I avoid it?
It is not a leak. #"bar" is a statically allocated string and thus foo doesn't need to be retained. You can handle these strings like autoreleased objects although they will resist in memory for the runtime of the application.
You can turn it into a leak by returning [foo retain] or [foo copy].
Technically it makes no sense to retain static variables. But if you copy them, you have to release them.
Short answer. This code will not give a leak.
Long answer:
With NSString it is not always visible leak, because of strings intern and because you do not call alloc/new/copy methods. But yes, this is a classic point of memory leak in general.
There are two ways of dealing with it.
tracing all objects that you are returning from this (or similar) method and releasing them. That's extremely buggy possibility and a very bad one almost every time.
returning autoreleased instance. In fact, you did something like it implicitly here. This string assignment is similar to:
NSString *foo = [NSString stringWithString:#"bar"];
And this one is similar to:
NSString *foo = [[[NSString alloc] initWithString:#"bar"] autorelease];
So, you will return an object, that has retain count 1, but is autoreleased. So, when NSAutoreleasePool will be drained, this object will go away.
So, I'm fairly certain that if I plan on manipulating strings often, such as with stringByAppendingString, I should be using variables of type NSMutableString.
But what if I'm doing something like this?
UILabel *someLabel = [[UILabel alloc] init];
[someLabel setText: [[someDictionary objectForKey:#"some_key"] stringByAppendingString:#"some other string"];
I read that if you use stringByAppendingString on an NSString, you end up with leaks because the pointer associated with the initial NSString moves around, pointing to the new string created by the append, whereas with NSMutableString, your pointer always points to that mutable string.
So my question is, what is implicitly happening when I call stringByAppendingString on something that is a string, but not explicitly an NSString or an NSMutableString? Such as, in my above case, the value of some key in a dictionary. Is doing this wrong, and should I be doing something like below?
[[[NSMutableString stringWithString:[someDictionary objectForKey:#"some_key"]] stringByAppendingString:#"some other string"]]
I read that if you use
stringByAppendingString on an
NSString, you end up with leaks
because the pointer associated with
the initial NSString moves around,
pointing to the new string created by
the append, whereas with
NSMutableString, your pointer always
points to that mutable string.
That sounds like the advice of someone who didn't quite have a grasp of what is going on with the memory management. Sure, [NSString stringByAppendingString] returns a new string. But what you do with that new string is up to you. You could certainly cause a memory leak by reassigning the result to a retained property in a careless fashion, like so:
myStringProperty = [myStringProperty stringByAppendingString:#" more bits"];
The correct form would be to use self, like so:
self.myStringProperty = [myStringProperty stringByAppendingString:#" more bits"];
Follow the cocoa memory guidelines.
As for dictionaries and other collection types: treat what comes out of the dictionary appropriately given the type you know it to be. If you pull an object out which is actually an NSString, but try to use it as a NSMutableString, your app will fall over (with 'selector not found' or similar). So in that case, you do need to make a new NSMutableString from the NSString.
Interesting note: Apple chose to make NSMutableString a subclass of NSString. Something about that seems unwise to me -- if something looks to be immutable, because it has type NSString, I want it to be immutable! (But in fact it could be NSMutableString.) Compare that to Java, which has a String class and a completely separate BufferedString class.
I've always been a fan of [NSString stringWithFormat#"%#%#", a, b]; because then you clearly get a new autoreleased string and can dispose of "a" and "b" correctly.
With [someDictionary objectForKey:#"some_key"], you will be getting the type of object that was put into that dictionary originally. So blindly calling stringByAppendingString without knowledge of what's in that dictionary seems like a bad idea.
-stringByAppendingString is going to return you a new NSString that is distinct from both strings involved. In other words:
NSString *string3 = [string1 stringByAppendingString:string2];
string3 is an entirely new string. string1 isn't changed at all, nothing happens to its memory location or contents. The person who told you that probably just misunderstood what was going on.
[mutableString1 appendString:string2];
In this case, mutableString1 still points at the same object, but the contents of that object have been altered to include string2.
One last thing to keep in mind is that if you are using mutable strings, you should be careful with sharing references to it. If you pass your mutable string to some function which keeps a pointer to that mutable string and then your code changes that mutable string at some point in the future, the other reference is pointing at exactly the same object which means the other code will see the change as well. If that's what you want, great, but if not you must be careful.
One way to help avoid this problem is to declare your #property statements for NSStrings to be "copy" instead of "retain". That will make a copy of your mutable string before setting it in your property and the -copy method implicitly gives you a NON-mutable version, so it'll create an NSString copy of your NSMutableString.
If you follow the rules for memory management, you will be fine using stringByAppendingString. In a nutshell:
if you own an object, you need to release or autorelease it at some point.
you own an object if you use an alloc, new, or copy method to create it, or if you retain it.
Make sure you read up on Apple's Memory Management Rules.
In the first code sample in your question, you aren't using alloc, new, copy or retain on any of the NSStrings involved, so you don't need to do anything to release it. If outside of the code that you've included in the sample you are using alloc, new, copy or retain on any NSStrings, you would need to ensure that they are released later.
I have a question about a retain and a NSString, if I have a method who a return a NSString, and I put the return NSString in a nsstring variable, I must do a retain or not?
NSString *myString = #"";
myString = [self methodWhoReturnString]; // I must do this?
myString = [[self methodWhoReturnString]retain]; // Or I must do this?
The Apple Developer Documentation on Memory Management explains the scenarios where you retain/release objects.
Simply put, if you want the string to stick around, you need to retain it until you're finished with it. If that is just the scope of the current function, you can get away without retaining it as if the string is already autorelease'd (likely) it won't get released until your function finishes and the current AutoReleasePool is purged.
Bear in mind that an NSString * could actually be pointing to an NSMutableString *. If it matters to you if the string is changed by some other function without you realizing, be sure to copy it: NSString * myCopyOfString = [mystring copy];
If the string is set to autorelease, which it most likely is, then yes you will need to retain it somehow. I would suggest doing this though:
myString = [[self methodWhoReturnString] copy];
this ensures you have retained the data in the string not just a reference to a string that might still be controlled elsewhere. Be sure you release your copy later!
Usually, methodWhoReturnString would return an autoreleased string, which means you should retain it if you want to keep it around.
So, if methodWhoReturnString is your method, I believe that to keep with convention you should return [stringToReturn autorelease]; from that method, and then retain it if you want to keep it.
You use retain if you're going to be using myString at a later point in time (i.e. after the current method has returned) to prevent it being autoreleased.
You don't need to use retain if it's just a temporary variable used within the current method, since in that case you do want it to be autoreleased.
One special case is properties. If you call self.blah = foo, you don't need to retain foo, since the setBlah: method should do it for you.
(there's a whole load of other complexities and edge cases, but this is a good rule of thumb to get you started on understanding what to do)
Given the code you provided, you shouldn't call -retain. In your example, the return value of a method that returns an instance of NSString is assigned to myString, an automatic local variable. If the assignment had been made to an instance variable or a static variable, you would want to call either retain or copy to guarantee that the reference remains valid beyond the end of the local scope.
In this case though, the reference to the NSString instance is stored in a variable that will be destroyed automatically at the end of the local scope, so your code needn't concern itself with the object's lifetime.
Any method that has alloc, new or copy in it automatically retains and infers that you have ownership of the object. All others shouldn't. It would be helpful if you had more context though. If we are in a contained method where this string is used briefly, then you probably don't need to retain. If it is going to be used for a while, you might want to use the #synthesize syntax to make it a property of the class you are in. When you use #property and #synthesize and call something like self.myProperty = something it will automatically retain.
That's somewhat confusing. NSMutableString inherits from NSString, but does that also mean that I can pass an NSMutableString anywhere safely where actually an NSString is wanted? And can I assign an NSString to an NSMutableString? How would I get an NSString out of an NSMutableString to avoid problems, if any?
Yes, you can pass an NSMutableString for an NSString. However, be aware that if the object you pass it to stores a reference to this object, it will "see" all the changes you make to the mutable string object. This is not always desirable.
No, not possible. If you had a NSMutableString pointer pointing to an NSString and called, say, appendString: on it, the object wouldn't know how to process the call.
(the first two are OO inclusion polymorphism basics)
If you want to get a non-mutable string from a mutable one, use [mutableString copy].