String objects as arrays
NSString is a class that supports the creation and management of immutable arrays of Unicode characters. Immutable means that once we make a string, it cannot be changed. The
NSMutableString provides an interface for the creation and manipulation of mutable strings, those whose contents we can change after they have been created. Because of this, we will find that working with strings is much like working with arrays.
Think back to the way strings are handled in C; they too are nothing more than character arrays. This is evident in the syntax where C strings are declared in one of the following two manners (both of which are two equivalent ways of declaring C arrays):
char aCString = "This is a C string, as well as an array";
char *anotherCString = "And here's another one.";
So you see, fundamentally, strings in Cocoa are very closely related to strings in C. The difference is in the way we interact with them, which is a direct consequence of Cocoa being object oriented.
NSString provides us with many higher level methods of interaction and behaviors, whereas in C we are stuck with the primitive elements of the language that allow us to access characters at some particular index, or to find the length of the array.
NSString has two primitive methods upon which the higher-level methods are based. They are
-characterAtIndex:, which we easily associate with our knowledge about C strings and arrays. (As an aside -- and I'll talk about this in more detail in a later column -- when you subclass an abstract class, which is the interface to a class cluster, the primitive methods of that class are the only ones you must override for the subclass to function normally.)
I digress; back to some more practical matters.
A cadre of methods
As I mentioned before, the easiest and most convenient way to create a string -- if you know ahead of time what the contents will be -- is the
@"..." construct. In the more traditional fashion of Objective-C object creation, you can create a new string using a number of
init... methods. Of course, you can create a blank string simply by doing:
NSString *aBlankString = [[NSString alloc] init];
But why waste time? A newly allocated string is easily given some meat with the
initWithString: method, which essentially copies an existing string (the argument, which is often of the
@"..." nature) into a newly allocated instance of
NSString (the receiver). This works in the following manner:
NSString *aString = @"Hello again.";
NSString *anotherString = [[NSString alloc] initWithString:aString];
Equivalently, we could have shortened this:
NSString *anotherString = [[NSString alloc] initWithString:@"Hello, again."];
Remember from the third column that creating new objects requires two steps: allocating the necessary memory by calling the
+ alloc class method, and then initializing it to some new value.
We can also create new string instances from standard C strings (which, as we just learned, are arrays of byte-sized
char strings) with the
- initWithCString: method, shown here:
char aCString = "Hello again.";
NSString *aCocoaString = [[NSString alloc] initWithCString:aCString];
Remember, we could have also defined our C string using the pointer syntax of arrays:
char *aCString = "Hello again";
I stress this duality only because the bracket-array syntax is more familiar to most, yet the pointer-array syntax is the standard way of referring to C strings in the
NSString class reference.
It is also possible to create formatted stings. The formatting I refer to here is the standard C formatting that is used in the C
printf statement. Formatted strings allow you to interject variable values into a string by using special placeholders. These placeholders, indicated by a percent sign (
%) and a character, specify the C data type (
char) of the variable whose value is to be displayed in that place. The string format is then followed by a series of arguments that are the variables to put in the respective placeholder. For example, we might have the following formatted string that creates a string with two variables:
int n = 3;
int m = 4;
NSString *aFormattedString = [[NSString alloc] initWithFormat:@"Hello, again, %i times over. The next one will be %i.", n, m];
If we were to display this in a text field, it would look like this:
Hello again, 3 times over. The next one will be 4.
All the rules for creating formatted C strings in the
printf statement apply here. For more information on the formatting options, check out the man page for
printf by typing
man printf in a terminal window.
Here we saw our first example of a method with optional arguments. We learned previously that non-optional arguments in a method are indicated by a "
:". On the other hand, commas separate optional arguments.
I also want to tell you about creating strings from a text file. The
NSString method that accomplishes this is
initWithContentsOfFile:. The argument of this method is an
NSString object indicating the absolute path of the file. (Later in this article, I'll tell you about some
NSString methods that help you manipulate path strings.) So, if I wanted to create a string that contains the contents of a file in my home directory, we would do the following:
NSString *path = @"/Users/mike/textFile.txt";
NSString *contentsOfFile = [[NSString alloc] initWithContentsOfFile:path];
This method interprets the file as being encoded in the standard C encoding.
Finally, I need to say something about the class methods of
NSString that allow us to create temporary strings (when I speak of temporary strings, I mean strings that are removed from memory shortly after they are created. We'll talk about this more when we get to memory management. In short, if you want the string object to stick around indefinitely, use the
alloc/init... two-step object creation procedure. Otherwise, if you just temporarily need to create a string to copy somewhere else, one of other the class methods are what you need).
It is often useful or necessary to create a string that will be used immediately and then discarded (for example, a string that will immediately be displayed in a text field. This will all make more sense when we talk about memory management). In this case you can use any of the
+string... class methods for
NSString. The majority of Cocoa classes follow the convention that temporary objects of that class are created using the class methods that begin with the type of object being made (i.e.
+ stringWith...). Most of the
init... methods have a matching class method to create temporary strings. So, if we wanted to create a temporary string from a C string, we would use the
+ stringWithCString: method:
[textField setStringValue:[NSString stringWithCString:"Hello again, and again"]];
Writing strings to a file
We saw above how we could make a new string from a plain text file, and we'll see now that the reverse is also possible; we can take a string and write it to a file using the
- writeToFile:atomically: method. The first argument of this method is a string that is the path to the file we wish to write our string to (we'll see later how we can work with paths as strings).
The second argument,
atomically:, is a a boolean value, so it is either "yes" or "no". If the
atomically flag argument is set to "yes", the method will not overwrite an existing file located at path. Additionally, the file will not be created until the method knows that file creation will be successful. We can implement this method in the following way:
NSString *path = @"/Users/mike/textFile.txt";
NSString *contenstOfFile = @"This string will end up on disk in the next line of code.";
[contentsOfFile writeToFile:path atomically:YES];
What we did was first create a string that is the path to the file we wish to write to, and then use that when we send the
writeToFile:atomically: message to the string we wish to put on disk.