Working with String Objects in Objective-C
Strings are collections of characters that are grouped together to form words or sentences. If it wasn't for humans, computers would probably never have anything to do with strings. The fact is, however, that one of the primary jobs of a computer is to accept data from and present data to humans. For this reason it is highly likely that any Objective-C program is going to involve a considerable amount of code specifically designed to work with data in the form of strings. The purpose of this chapter is to cover the key aspects of string creation, comparison and manipulation in Objective-C using the Foundation Framework's NSString class.
Strings without NSString
As we've already discussed, Objective-C is built upon the C programming language. C also has a mechanism for dealing with strings, but because C is not an object oriented programming language it does not have any of the advantages offered to us through the NSString class. For example, to use the C approach to creating strings we have to set up a pointer to a string of characters:
char *myString = "This is a C character string";
Alternatively, we could define a C style character array to contain a string:
char myString[] = "This is a C character array";
Having created the string we literally have nothing but a section of memory where a null terminated string of characters is located. If we want to do anything to manipulate the string we will have to write our own code to do it.
By using NSString, however, we get access to a wide range of methods provided with that class to manipulate our string without having to write all the code ourselves. My first ever job involved writing complex programs in the C programming language, and from bitter experience I can tell you that the hardest part of that job was writing code to work with strings. My life would have been much easier if Objective-C and the NSString class had existed all those years ago.
In addition, C style character strings are composed of single byte characters and therefore limited in the range of characters that can be stored. This usually becomes a problem when dealing with non-ASCII character sets used by foreign languages. NSString objects, on the other hand, are comprised of multibyte Unicode characters and can handle just about any language character set.
Declaring Constant String Objects
A constant string object is declared by encapsulating the string in double quotes (") and preceded by an @ sign. For example:
@"This is a constant character string object";
In order to display the current value of a string object using the NSLog methods, simply reference the string using '%@' as follows:
NSLog (@"%@", @"This is a constant character string object");
Even though all we are doing here is creating a constant string object, keep in mind that this is still an object. As such, it has a range of methods that we can call on it. For examples string objects have a length methods that returns the number of characters in the string. We can, therefore, call this on a constant string object:
int len = [@"Hello" length]; NSLog (@"Length of string = %i", len);
The above code declares a constant string object containing the word "Hello" and calls the length method of object. The result is assigned to an integer variable named len which in turn is displayed using NSLog. When compiled and executed, we get the following output:
Length of string = 5
Constant string objects are actually instantiated from the NSConstantString class which, much like the other classes we will look at in this chapter, is actually a subclass of the NSString class. In practice, given the way that constant strings are used, it is unlikely that you will need to specifically declare your string constants as being of type NSConstantString. It is more likely that you will declare the string as we have done in this section and let the compiler handle the rest.
Creating Mutable and Immutable String Objects
Two additional types of Objective-C string objects are mutable and immutable. When you create a string object of type NSString you are creating an immutable string object. This means that once a string has been assigned to the object, that string cannot subsequently be modified in any way.
NSString *string1 = @"This string is immutable";
Mutable string objects, on the other hand, are declared using the NSMutableString class and allow the string contained within the object to be modified using a variety of methods (some of which will be covered in the remainder of this chapter). NSMutableString is a subclass of NSString, which in turn is a subclass of NSObject. Mutable strings cannot be initialized simply by assigning a constant string object as we did above since that will just give us a pointer to an immutable constant string object. Instead, the string constant must be copied into the mutable string object. For example:
NSMutableString *string2 = [NSMutableString stringWithString:@"This string is mutable"];
Once a string has been declared as immutable, the only way to get a mutable version of the string is to create a mutable string object and copy the contents of the immutable string object to it. This can be achieved using the NSMutableString stringWithString class method. For example:
NSString *string1 = @"This is a string"; NSMutableString *string2; string2 = [NSMutableString stringWithString: string1];
Once executed, the above code will create an immutable string object (string1) initialized with the text "This is a string" and an empty pointer to an immutable string object (string2). The stringWithString class method of the NSMutableString class is then called, passing though the immutable string1 as an argument. This method returns a new object containing the immutable string and assigns it to string2. We now have a mutable copy of the immutable string1 object.
Getting the Length of a String
The length of the string in a string object can be obtained by accessing the length method of the string object:
NSString *string1 = @"This string is Immutable"; int len = [string1 length]; NSLog (@"String length is %i", len);
The above code fragment will produce the following output when executed:
String length is 24
Copying a String
When copying one string object to another it might be tempting to think that you can simply assign the object from one variable to another. For example, if we had two integer variables and wanted to assign the value of one to the other we could simply do the following:
int a = 10; int b; a = b;
After the above code has executed, both variables a and b will contain the value 10. The same is not, however, true of string objects. Take for example the following code fragment:
NSMutableString *string1; NSMutableString *string2; string1 = [NSMutableString stringWithString: @"This is a string"]; string2 = string1;
What we have achieved here is to create two variables (string1 and string2) that point to the memory location of the same string object. This is because the '*' before the variable names in the declarations indicates that this is a pointer to an object, not an actual object. Any time that we access the object referenced by either of these pointers we will, in fact, be accessing the same object. To prove this, we can make a change using the string2 reference and then display the string associated with both the string1 and string1 object pointers:
NSMutableString *string1; NSMutableString *string2; string1 = [NSMutableString stringWithString: @"This is a string"]; string2 = string1; [string2 appendString: @" and it is mine!"]; NSLog (@"string1 = %@", string1); NSLog (@"string2 = %@", string2);
The above code will display the following output, proving that both string1 and string2 point to the same object since only one reference was modified, yet both show the change:
2009-11-03 14:35:37.731 t[32239:10b] string1 = This is a string and it is mine! 2009-11-03 14:35:37.732 t[32239:10b] string2 = This is a string and it is mine!
To actually copy one string object to another string object we must use stringWithString method the NSMutableString class:
NSMutableString *string1; NSMutableString *string2; string1 = [NSMutableString stringWithString: @"This is a string"]; // Initialize string1 string2 = [NSMutableString stringWithString: string1]; // Copy string1 object to string2 [string2 appendString: @" and it is mine!"]; // Modify string2 NSLog (@"string1 = %@", string1); NSLog (@"string2 = %@", string2);
When executed, the appended text appears only in the object referenced by string2 since string2 now references a different object to that referenced by string1:
2009-11-03 14:42:10.426 t[32263:10b] string1 = This is a string 2009-11-03 14:42:10.427 t[32263:10b] string2 = This is a string and it is mine!
Searching for a Substring
A common requirement when working with string is to identify whether a particular sequence of characters appears within a string. This can be achieved using the rangeOfString method. This method returns an structure of type NSRange. The NSRange structure contains a location value providing the index into the string of the matched substring and a length value indicating the length of the match.
NSString *string1 = @"The quick brown fox jumped"; NSRange match; match = [string1 rangeOfString: @"brown fox"]; NSLog (@"match found at index %i", match.location); NSLog (@"match length = %i", match.length);
The NSLog call will display the location and length of the match. Note that the location is an index into the string where the match started and that the index considers the first position in a string to be 0 and not 1. As such, the location in our example will be 10 and the length will be 9.
In the event that no match is found, the rangeOfString method will set the location member of the NSRange structure to NSNotFound. For example:
NSString *string1 = @"The quick brown fox jumped"; NSRange match; match = [string1 rangeOfString: @"brown dog"]; if (match.location == NSNotFound) NSLog (@"Match not found"); else NSLog (@"match found at index %i", match.location);
Replacing Parts of a String
Deleting Sections of a String
Extracting a Subsection of a String
Appending Text to the End of a String
Text can be appended to the end of an existing string object using the appendString method. This method directly modifies the string object on which the method is called and as such is only available for mutable string objects.
NSMutableString *string1 = [NSMutableString stringWithString: @"The quick brown fox jumped"]; [string1 appendString: @" over the lazy dog"]; NSLog (@"string1 = %@", string1);
Comparing Strings
Checking for String Prefixes and Suffixes
A string object can be tested to identify whether the string begins or ends with a particular sequence of characters (otherwise known as prefixes and suffixes). This is achieved using the hasPrefix and hasSuffix methods respectively, both of which return boolean values on whether a match is found or not.
NSString *string1 = @"The quick brown fox jumped"; BOOL result; result = [string1 hasPrefix: @"The"]; if (result) NSLog (@"String begins with The"); result = [string1 hasSuffix: @"dog"]; if (result) NSLog (@"String ends with dog");
Converting to Upper or Lower Case
The Foundation NSString classes provide a variety of methods for modifying different aspects of case within a string. Note that each of these methods returns a new string object reflecting the change, leaving the original string object unchanged.
- capitalizedString
Returns a copy of the specified string with the first letter of each word capitalized and all other characters in lower case:
NSString *string1 = @"The quicK brOwn fox jumpeD"; NSString *string2; string2 = [string1 capitalizedString];
The above code will return a string object containing the string "The Quick Brown Fox Jumped" and assign it to the string2 variable. The string object referenced by string1 remains unmodified.
- lowercaseString
Returns a copy of the specified string with all characters in lower case:
NSString *string1 = @"The quicK brOwn fox jumpeD"; NSString *string2; string2 = [string1 lowercaseString];
The above code will return a string object containing the string "the quick brown fox jumped" and assign it to the string2 variable. The string object referenced by string1 remains unmodified.
- uppercaseString
Returns a copy of the specified string with all characters in upper case:
NSString *string1 = @"The quicK brOwn fox jumpeD"; NSString *string2; string2 = [string1 uppercaseString];
The above code will return a string object containing the string "THE QUICK BROWN FOX JUMPED" and assign it to the string2 variable. The string object referenced by string1 remains unmodified.