i created an NSMutableString with the method stringWithCapacity:5
How do i test if characterAtIndex:0 is empty
Empty string contains no characters, even if you created it with non-zero capacity. To check if string is empty simply check its length:
if ([myString length] == 0){
// empty
}
Moreover, trying to access a character at index which is >= of string's length will result in NSRangeException exception.
The *WithCapacity methods that we see on NSString, NSArray, etc, have nothing to do with pre-populating the contents of the object. They are simply a means by which you can suggest to the object how much it's going to hold. If you suggest a large enough number, it may use a different storage mechanism than if it were a small number.
So in other words, you could do [NSMutableString stringWithCapacity:1234567890] and it give you exactly the same thing as if you had simply done [NSMutableString string], and the -length of the resulting object will always be 0.
Frankly, the *WithCapacity methods are pretty useless. I've never found a reason to use them.
Related
I would like to understand more about the way XCode/Objective-C handle constant strings. I found a related question, but I would like more information. Consider the following code:
NSString *a = [[NSString alloc] initWithUTF8String:[[_textFieldA stringValue] UTF8String]];
NSString *b = [[NSString alloc] initWithUTF8String:[[_textFieldB stringValue] UTF8String]];
NSString *c = [a copy];
NSString *d = [a mutableCopy];
Note that the textFields are just a way to set the strings at runtime ensuring that the compiler doesn't get too smart on me and build in a single instance.
If my text fields are empty, or contain a single character such as "x" or "$", then a == b == c == the same constant NSString instance. If I instead provide "xy", then a == c != b. d is always unique, as one might expect since it is mutable.
Now normally this wouldn't be an issue, I'm not trying to modify the contents of these strings, however, I am working on a system where I frequently use objc_setAssociatedObject. So here now I might come accross an empty string, and then set associated object data on it, and then have another empty string and collide with the first.
I have, for the moment, solved my issue by creating mutable strings instead.
So my questions:
Is this an Objective-C specification, or an XCode excentricity?
Does anyone know how the instance is determined? Why "x" get's one instance, but not "xy"? I would think some internal dictionary is involved and there's no good reason to stop at 1 character.
Is there a way to turn this off, so all empty strings are unique instances, or other suggestions?
I am using XCode 5.1.1, OSX 10.9.4, SDK 10.9.
Thank you!
Is this an Objective-C specification, or an XCode excentricity?
It is just implementation detail. Not documented any where. These kind of behaviour may changed in future without notice.
Does anyone know how the instance is determined? Why "x" get's one instance, but not "xy"? I would think some internal dictionary is involved and there's no good reason to stop at 1 character.
No until someone able to access source code want to share the details with us.
Is there a way to turn this off, so all empty strings are unique instances, or other suggestions?
No way to turn it off. Don't use objc_setAssociatedObject with NSString
As #Ken Thomases said in comment
In general, it probably doesn't make sense to use objc_setAssociatedObject() with any value class.
Some other examples are NSNumber, NSData and NSValue. They are often cached and reused.
I have a NSMutableArray consisting out of NSStrings. When I need to sort it, I use [array sortUsingSelector:#selector(caseInsensitiveCompare:)] which works perfect.
But sometimes I need to sort the array by substrings of NSStrings. The substring is defined in this case as part of NSString following some marker. The thing is complicated further by the fact that marker can be positioned differently in every string.
Obviously I can break NSString into 2 objects and do sorting on them but it will require significant changes.
Is there a way to do the sorting using selector similar to what I have described above?
I think if not, then I might sort by creating a sorted copy of an array (instead of using selector to do it in place), then releasing the original.
You can perform any arbitrarily complex sorting inline with NSMutableArray's sortWithOptions:usingComparator:
[myMutableArray sortWithOptions:NSSortStable usingComparator:^NSComparisonResult(NSString* str1, NSString* str2) {
// Scan for your marker in both strings and split on it...
// Say you store the results in substr1 and substr2...
return [substr1 caseInsensitiveCompare:substr2];
}];
I need to use a bunch of string variables throughout my program. I reassign some of them quite often, while others are stuck with the same value during execution.
What's the best practice here?
In the first case, the variables should be NSMutableString and I should cast them to NSString (using the copy method) whenever they need to be arguments of functions that require NSString objects. Is that right?
When I reassign them to other constant values, I shouldn't have to dispose the previous content, right?
As for NSString objects, if I need to assign a new value to them, I guess I should deallocate them, allocate them again, and then assign the new value. Is that correct?
Unless you're actually modifying a string, you shouldn't use NSMutableString. You're reassigning the whole string to a new value, so stay with a regular NSString. Use the autoreleased versions, because that'll be more efficient than alloc/init/release all the time. You could also just reassign your strings to constants if you know what they'll be assigned to.
In the first case, the variables should be NSMutableString and I should cast them to NSString (using the copy method) whenever they need to be arguments of functions that require NSString objects. Is that right?
Well, you could do it that way, but it would be really inefficient. Remember inheritance—an NSMutableString is an NSString, just with some new stuff tacked on. A simple cast will do the trick:
NSString *string = (NSString *)aMutableString;
Even better though, you don't even have to do that. Because of inheritance, you can directly pass in a mutable string wherever a regular string is required, no casting required. That's the beauty of inheritance.
When I reassign them to other constant values, I shouldn't have to dispose the previous content, right
For neither mutable or immutable strings. Old values are simply overwritten in memory—nothing to dispose of there. As far as the memory management goes, it's really not efficient to literally be creating new strings all the time. Just reassign them. You will never need to alloc/init one string more than once, and that single init should be balanced by a single release.
Addendum: When Should You Use Mutable?
A mutable string should be used when you are physically changing the value of the existing string, without completely discarding the old value. Examples might include adding a character to the beginning or the end, or changing a character in the middle. With a mutable string, you can do this "in place"—you'll just modify the existing string. By contrast, an immutable string, once its value is set, cannot change that value. NSString has methods such as stringByAppendingString:, which does add a string to an existing one—but it returns a new string. Behind the scenes, NSString has copied your old string to a new (larger) memory location, added the argument, and returned the new string. That copying is a lot less efficient (relatively speaking, or if you have to do it a lot).
Of course, there's nothing stopping you from physically assigning one string to another. Old values will be overwritten. Most NSStrings, including the #"String Constants", are autoreleased. If you are creating a new string and you decide to alloc/init, you can then assign it to another value without consequence:
myString = anotherString;
myString = myTextField.text;
You can do this with both mutable and immutable strings. The main takeaway is that you should only use mutable when your changing the string itself. But you can change the variable with both mutable and immutable strings without compiler or runtime issues (short of memory management, but most of it is autoreleased anyway).
As for NSString objects, if I need to
assign a new value to them, I guess I
should deallocate them, allocate them
again, and then assign the new value.
Is that correct?
You don't deallocate NSString if you didn't allocated it before, like here:
NSString *string = [NSString stringWithFormat:#"Hello"];
You only need to deallocate it when you call alloc:
NSString *string = [[NSString alloc] initWithString:#"Hello"];
[string release];
The only difference between NSMutableString* and NSString* is that mutable string can be changed.
You don't have to cast anything, since NSMutableString is a subclass of NSString, nor take different memory measures ( so you are right * ).
If you need a modifiable version of a string you just do
NSMutableString* myMutableString = [NSMutableString stringWithString:myString];
You should not 'copy' anything.
Note that if you call :
NSString* myString = myMutableString;
myString is still a mutable String.
So if for any reason (security...) you relly need unmutable strings, you have to call
NSString* myString = [NSString stringWithString:myMutableString];
* you are right, but you could also call [replaceCharactersInRange:withString:] on the mutable string. if there is enough space from previous allocation, then it may be faster, since there is no destruction and new allocation to do.
( Added later : forgot the setString: method )
I'm writing an iPhone application that uses a lot of editable text fields. I've been learning a lot about UITextFields and NSStrings by reading various references online, but there are some details that still elude me. When a user puts in an incorrect value for one of my text fields, I throw up an error message and put the text field back to the way it was before their input. For empty text fields, I've been doing this:
theTextField.text = #"";
Is this the best way to do this? I just came up with the idea myself, I don't know if there are any problems with it (other than the fact that it seems to work just fine so far).
Also, does #"" have the same value as a "nil" string? In other words, if I set a string to #"" and then call this:
if (myString) {...}
will the statement return true or false?
One last thing. When an NSString is initialized using this:
NSString *myString = [[NSString alloc] init];
what is that string's Length value?
The important thing to understand here is that an NSString with no characters in it, such as #"" or [[NSString alloc] init] is still a valid object. All the consequences that Nick has stated follow from that.
In Objective-C, any valid object will be "True" in a boolean context;* nil is the only false object value.
Since these strings are valid objects, they do have a length, but because they contain no characters, the length is 0.
There are no problems with assigning an empty string object #"" to another string pointer, such as the text of your text field. Since the string with no characters is still a valid NSString object, this is exactly the same as assigning a string which does happen to have characters.
*Unlike so-called "scripting" languages like Python or Perl, where an empty string or collection evaluates to boolean false.
Using
theTextField.text = #"";
is absolutely ok. There should be no problems at all.
if (#"")
will evaluate to true. #"" is not the same as nil.
The length of
NSString *myString = [[NSString alloc] init];
is 0.
This is not an answer to the question, but may be the answer to what you're trying to do.
If you're wondering whether you have to write if(str && str.length) to cover both nil and empty strings, you don't. You may use just if(str.length), since, in Objective-C, unknown messages to nil will return nil (so [a.b.c.d.e.f doStuff] will be nil if any of those values in the chain is nil). There is thus scarce need for specific nullity checks, unless what you want is precisely to determine nullity.
Check NSString's + string.
In the Pragmatic Core Data book, I came across this code snippet for an NSString setter:
- (void)setMyString:(NSString*)string;
{
#synchronized(self) {
if ([string isEqualToString:myString]) return;
[myString release];
myString = [string retain];
}
}
Is there any reason to use [string isEqualToString:myString] instead of string == myString here? Does it not mean that if the two strings have the same content, the result will be different than if they are actually the same object? Does this matter?
Thanks.
Notice that the variables you're comparing are pointers to NSStrings. Pointer comparison just checks if the pointers are referring to the same address. It doesn't know anything about the content at the end. Two string objects in two different places can have the same content. Thus you need isEqualToString:. In this case, I'm not sure either that it's a terribly important distinction to make though. It would make more sense to me if it were special-casing sending out change notifications based on whether the new string would actually be a change.
Incidentally, in an NSString setter, you almost always want copy rather than retain. I don't know the exact use case in this book, but if you just retain the string and it happens to be mutable, it can change behind your back and cause weird results. And if the string isn't mutable, copy is just an alias for retain.