For non-retained string declarations, are these three lines the same?
NSString *list2 = self.map;
NSString *list2 = [NSString stringWithFormat:#"%#", self.map];
NSString *list2 = [NSString stringWithString:self.map];
They all create an autoreleased string object, right? Is there a preferred method among these, or are there any differences in the memory usage or behavior of "list2" depending on these methods?
For some reason, I find the manipulation of strings in objective-C the most confusing transition from other languages.
The simple fact, You don't own the object in the above three cases,
So you could use either,
This is more related to choice of developer then performance.
Go through the Memory Management Programming Guide
They all create an autoreleased string object, right?
No, the first one merely assigns the pointer returned by string.map to list2. The second and third ones theoretically create new NSStrings that you don't own and assign them to list2. However, if string.map returns an immutable string, the third one will probably give you the same pointer (possibly retained and autoreleased).
In all cases you do not own the (new) string. That's actually all you need to know. They may be autoreleased, but it is not relevant to you using them.
Related
I'm pretty new to iOS development, and I want to figure out if there's a good way to handle this issue. Basically, I'm making a technical calculator that returns some product specifications based on user input parameters. The product in question has specs for some, but not all user parameters, so I . In a constants file, I have a bunch of ATTEN_SPEC_X variables which are const double or const NSString *. Now, it's perfectly okay to be missing a spec, so my plan was to leverage NSArray's ability to hold different types and use introspection later to handle strings vs doubles before I report the returned specs.
Here's an incomplete example of one method I'm implementing. It's just a big conditional tree that should return a two-element array of the final values of spec and nominal.
- (NSArray *)attenuatorSwitching:(double *)attenuator{
double spec, nominal;
{...}
else if (*attenuator==0){
spec=ATTEN_SPEC_3; //this atten spec is a string!
nominal=ATTEN_NOM_3;
}
{...}
return {array of spec, nominal} //not actual obj-c code
So instead of making spec and nominal doubles, can I make them some other general type? The really important thing here is that I don't want to use any special handling within this method; another coder should be able to go back to the constants file, change ATTEN_NOM_3 to a double, and not have to retool this method at all.
Thanks.
The problem you'll run into is that NSArrays can't directly handle doubles. However, you can get around this if you start using NSNumber instances instead - you can return an NSArray * containing an NSString * and an NSNumber * with no problems. If you need even more general typing, the Objective-C type id can be used for any object instance (though still not with primitives; you can't make a double an id).
Later, when you get an array, you can use the NSObject method -isKindOfClass: to determine the type of object you're pulling out of the array, and deal with the string or number depending on the resultant type. If you need to convert your NSNumber back to a double, just use the NSNumber instance method -doubleValue to unbox your double. (+[NSNumber numberWithDouble:] goes the other way, giving you an NSNumber out of a double.)
If you're using a recent enough version of Xcode, you can even make these things literals, rather than having to litter calls to +numberWithDouble: all over the place:
return #[ #3, #"number of things" ]
I find I usually directly use a NSString like:
self.text = #"word";
label.text = #"word";
function(#"word");
I think it is a wrong way to directly use NSString, because the #"word" will have a retainCount of 2 after it has been used. Is that right?
What is exactly the retainCount of #"" ? Is it an autorelease object or has a retain of 1?
What`s more, I encountered some memory leak as the pic shown below:
I suspect it is related to the direct use of the NSString.
Essentially, the retain count of NSString literals is infinite. The memory for these objects is reserved by the compiler at compile time and never gets released for the duration that your app is running, no matter how often you try to retain or release them.
This is another good example why it is wrong to care about retain counts. You should only care about the golden memory management rules: if you take ownership of an object (with alloc, new, copy or retain), you have to release or autorelease it later. Otherwise, you don't.
Quoting from String programming guide
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"/tmp/scratch";
Note that, when creating a string constant in this fashion, you should avoid using anything but 7-bit ASCII characters. 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.
the #"word" will have a retainCount of 2 after it has been used. Is that right?
No. This is a perfect illustration of why it is bad to think in terms of retain counts which are an internal implementation detail. You can think of string literals as strings that are "owned" by the executable image so they will not go away. You should treat them like any other Objective-C object.
If you do take a sneaky peek at the retain count of a string literal, you'll find it is set to some really big number (something like the maximum value for an NSInteger). This is treated as a special value by retain and release that they don't change.
The memory for string literals is allocated as part of the binary image at compile time. It can never go away. Your memory leak is not because of this.
No, it's a good thing to declare an autoreleased NSString by using directly #"". But NSString are retained in a particular way and it's not really possible to know what's being done at runtime. You may have weird retain count sometimes. Don't bother about your leak of 48 Bytes.... It's not related to your nsstring.
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've noticed that all #"" objects create one reference for all times it is executed.
NSString *s1=#"";
NSString *s2=#"";
In this sample s1 equals s2.
#"" will create one pointer in all cases, every time i use it?
Can i rely on this feature in comparing strings in objective-c?
Or simply, can i use this statement, if i want to assure that my string is empty:
if(s == #""){
//do something
}
Yes Objective C has an optimization in the compiler that simply points all equivalent string literals to the same string in memory to avoid allocating unnecessary resources. This feature is reliable but there is a chance that this will not always happen as documented in the Objective C language specs.
you should use
if([s isEqualToString:#""])
I'm just starting out with iphone development and ran across some example code that used #"somestring"
someLabel.txt = #"string of text";
Why does the string need the '#'? I'm guessing it's some kind of shortcut for creating an object?
It creates an NSString object with that string as opposed to the standard c char* that would be created without the '#'
In Objective-C, the syntax #"foo" is an immutable, literal instance of NSString.
Just an interesting side note... NSString literals created by using the #"..." notation are not autoreleased. They essentially just hang around until your program terminates.
Just a caution that if you want to maintain control over whether or not this object gets released (freed) down the road you may want to consider using something like:
[NSString stringWithString:#"..."];
...instead. This would create an autoreleased version of the same string that will be freed from memory next time the "autorelease pool is drained".
Just food for thought.
Cheers-