I have a NSString that will be passed as a parameter to my library's function, the NSString is passed by another library. The strange thing is, if I pass the NSString to the library call, the call will fail, but if I convert the NSString to int and then convert the int back to a NSString, every thing is fine.
But by printing it out using NSLog("%#"), the two strings are identical. What may cause this? Encoding?
When you
convert the NSString to int and then convert the int back to a NSString
you are basically creating a copy of the string, unrelated to the original one.
It would be interesting to know how you create the two strings to know what exactly happens. My guess is that the first one is deallocated too soon, so the call fails; the copy is retained and the call succeeds.
Just for a quick try:
when calling the function that is failing:
[self doMethodWithString:aString];
just do:
[aString retain];
[self doMethodWithString:aString];
If this works, then the memory management issue is confirmed, but for a real fix you should explain how you create the strings...
Related
I was just curious, is there any difference between the following two codes?
NSString *aString = [NSString stringWithString:#"a string"];
NSString *aString = #"a string";
I wonder what exactly is going on when you do the latter way.
Both point to a literal string created at compile time.
Even though stringWithString suggest it's autoreleased, a literal string will never get released.
See my related post here:
Difference between NSString literals
From the apple docs # https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/CreatingStrings.html
Such an object is created at compile time and exists throughout your
program’s execution. The compiler makes such object constants unique
on a per-module basis, and they’re never deallocated, though you can
retain and release them as you do any other object.
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.
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * str = [[NSString alloc] initWithString:#"test"];
[str release];
int i = 999999999;
while(i-- > 0) {}
NSLog(#"%#", str);
[pool drain];
Output: test
Why didn't release work?
How can I immediately delete the object from memory?
Xcode Version 4.0 iPhone Application
~SOLVED~
Thank's to all for answers.
I've got a lot of useful information about this question. I'm going to use NSString *str = #"text" instead of NSString *str = [[NSString alloc] initWithString:#"text"];
i've understood that release just "marks" memory as "willing to be freed", but not freeing it immediatly
It did work. You have relinquished ownership of that object, and when the system determines that it is no longer owned, it will be marked available for reuse by the system. That may happen immediately, if you were the only owner of the string. It may happen at some later point, if creation of the string caused it to be autoreleased internally. Or, as Dave DeLong points out, the system may optimize it into an object that is never released.
In your case, it's being optimized into a constant string, which will exist for the life of the program. If you were to use an NSMutableString instead of an NSString, you'd see funky behavior that would probably not crash, but wouldn't print what you expected. (See this question for an example.)
If you used an NSArray instead, it would be deallocated when you called release, but you'd still see your NSLog example work correctly until you allocated some other object. Deallocation just marks the memory as available for reuse; it doesn't actually clear it out. So if you passed the array to NSLog, that memory hasn't been changed and thus it still prints correctly.
The key point in all of this, though, is to recognize that calling release will not necessarily cause the object to be deallocated. It may continue to exist for any number of reasons. But once you call release, you have relinquished ownership of the object. If you continue using it after that point, the system is free to do all sorts of weird things at its own will, as demonstrated.
Release does work but what you are attempting to do has undefined behavior, and when using a NSString and a literal you may also get different behavior. What is happening is although your object is released the memory at that location is reclaimable and has not changed and when it goes to print it it is still valid. Since it is a NSString a message to description is not necessarily sent and that is why you are not getting an exception for attempting to message a deallocated object.
This question has some good information about NSString and NSLog.
When you do:
NSString * str = [[NSString alloc] initWithString:#"test"];
This gets optimized into:
NSString * str = #"test";
You can't release a constant string, because it's hardcoded into the application binary.
Proof:
NSString *s = [NSString alloc];
NSLog(#"%p", s);
s = [s initWithString:#"foo"];
NSLog(#"%p", s);
s = #"foo";
NSLog(#"%p", s);
Logs:
2011-04-12 10:17:45.591 EmptyFoundation[6679:a0f] 0x100116370
2011-04-12 10:17:45.599 EmptyFoundation[6679:a0f] 0x100009270
2011-04-12 10:17:45.604 EmptyFoundation[6679:a0f] 0x100009270
You can see that the result of +alloc is different from the result of -initWithString:, and the result of -initWithString: is equivalent to the constant string. Basically, -initWithString: says "aha, i'm going to be an immutable string, and I'm being given an immutable string! I can just take a shortcut, destroy myself, and return the parameter, and everything will still work the same"
You're using a bad pointer in you NSLog(). You happen to be getting lucky in this case, but you should expect code like this to crash or fail in other ways.
There is no need to delete the memory block, this will use up an unneeded cycle.
The memory will be overridden when an new object is allocated an occupy that memory block.
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 am trying to write text using a Core Graphics context. I can do it the first time, no problem, but the second time crashes my iPhone app. Here is a code snippet:
NSString *name = [MyClass getName];
const char *cname = [name UTF8String];
[self drawText:context text:cname];
MyClass and drawText are custom classes/methods but you get the idea. These three lines live in drawRect:
The first time drawRect: is executed, I see the text as expected. However, on any refresh of drawRect:, the line:
const char *cname = [name UTF8String];
causes my app to crash with the cryptic, "GDB: Program loaded." status message.
I get a similar response even when I use the getCString: method. I think I might be missing a fundamental understanding of NSString to char array conversion.
It sounds like you're trying to call methods on an object which has been deallocated already. The UTF8String message has the problem that you can't hold onto the returned pointer, since it may become invalidated when the string is released -- you have to copy the string if you need to hold onto it. However, getCString:maxLength:encoding: does not have that problem.
Make sure you're following properly memory management protocol. See the Memory Management Programming Guide for Cocoa, and double-check that you're sending retain, release, and autorelease messages to the proper objects at the proper times. Chances are you're sending an extra release or autorelease when you shouldn't be, or you're forgetting to retain your string somewhere.
The most likely cause is that you're keeping a reference to the previously returned char* and you are dereferencing it on the second call. According to spec, the pointer is not valid to store: The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.