Before you dive into the UIKit, the set of libraries for creating iOS applications, you’re going to write a command line tool that will let you focus on the Objective-C language. Open Xcode and select → → . In the lefthand table in the Mac OS X section, click Application and then select Command Line Tool from the upper panel, as shown in Figure 2.3. Click the Next button.
On the next panel, name the product RandomPossessions and choose Foundation as its type (Figure 2.4). Click Next, and you will be prompted to save the project. Save it some place safe – you will be reusing parts of this code in future projects.
One source file (main.m) has been created for you in the RandomPossessions group of the project navigator (Figure 2.5).
Click on this file to open it in the editor area, and you’ll see that some code has already been written for you – most notably, a main function that is the entry point of any C (or Objective-C) application.
Time to put your knowledge of Objective-C basics to the test. Delete the line of code that NSLogs “Hello, World!” and replace it with lines that create and destroy an instance of an NSMutableArray.
#import <Foundation/Foundation.h> int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Create a mutable array, store its address in items variable NSMutableArray *items = [[NSMutableArray alloc] init]; // Release the array [items release]; // Don't leave items pointing at freed memory! items = nil; [pool drain]; return 0; }
Once you have an instance of NSMutableArray, you can send it messages, like addObject: and insertObject:atIndex:. In this code, the receiver is the items variable that points at the newly instantiated NSMutableArray. Add a few strings to the array instance.
int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSMutableArray *items = [[NSMutableArray alloc] init]; // Send the message addObject: to the NSMutableArray pointed to // by the variable items, passing a string each time. [items addObject:@"One"]; [items addObject:@"Two"]; [items addObject:@"Three"]; // Send another message, insertObject:atIndex:, to that same array object [items insertObject:@"Zero" atIndex:0]; [items release]; items = nil; [pool drain]; return 0; }
When this application executes, it creates an NSMutableArray and fills it with four NSString instances. However, you need to confirm that you added the strings. In main.m, after adding the final object to the array, loop through every item in the array and print each one to the console.
int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSMutableArray *items = [[NSMutableArray alloc] init]; [items addObject:@"One"]; [items addObject:@"Two"]; [items addObject:@"Three"]; [items insertObject:@"Zero" atIndex:0]; // For every item in the array as determined by sending count to the items array for(int i = 0; i < [items count]; i++) { // We get the ith object from the array and pass it as an argument to NSLog, // which implicitly sends the description message to that object NSLog(@"%@", [items objectAtIndex:i]); } [items release]; items = nil; [pool drain]; return 0; }
Click the Run button. It may seem like nothing has happened because the program exits right away, but the log navigator tells another story.
The log navigator stores the build results and console output from each build of your application. To reveal the log navigator, select the icon or use the keyboard shortcut Command-7. Select Debug RandomPossessions at the top of the log navigator to see your console output in the editor area (Figure 2.6).
Now let’s go back and take a closer look at some of the code in your main function. First, notice the @"One" argument in the first addObject: message sent to items.
[items addObject:@"One"];
In Objective-C, when you want a hard-coded string, you prefix a character string with an @ symbol. This creates an instance of NSString (another Objective-C class) that holds the character string.
But, wait – aren’t instances created by sending alloc to a class? That is the way most objects are created, but the @ prefix is a special case for the NSString class. It is convenient shorthand for creating strings.
The following code shows three such uses, and each is completely valid Objective-C, where length is an instance method on NSString:
NSString *myString = @"Hello, World!"; int len = [myString length]; len = [@"Hello, World!" length]; myString = [[NSString alloc] initWithString:@"Hello, World!"]; len = [myString length];
Next, let’s look at the function NSLog we used to print to the console. NSLog takes a variable number of arguments and prints a string to the console. The first argument is required and must be an NSString instance. This instance is called the format string, and it contains text and a number of tokens. Each additional argument passed to the function replaces a token in the format string. The tokens (also called format specifications) must be prefixed with a percent symbol (%), and they specify the type of the argument they correspond to. Here’s an example:
int a = 1; float b = 2.5; char c = 'A'; NSLog(@"Integer: %d Float: %f Char: %c", a, b, c);
The order of the arguments matters: the first token is replaced with the second argument (the format string is always the first argument), the second token is replaced with the third argument, and so on. The console output would be
Integer: 1 Float: 2.5 Char: A
In C, there is a function called printf that does the same thing. However, NSLog adds one more token to the available list: %@. When %@ is encountered in the format string, instead of the token being replaced by the corresponding argument, that argument is sent the message description. This method returns an NSString that replaces the token. Because the argument is sent a message, that argument must be an object. As we’ll see shortly, every object implements the method description, so any object will work.
What exactly is this NSMutableArray you’ve been using? An array is a collection object (also called a container). The Cocoa Touch frameworks provide a handful of collection objects, such as NSDictionary and NSSet, and each has a slightly different use. An array is an ordered list of objects that can be accessed by an index. Other languages might call it a list or a vector. An NSArray is immutable, which means you cannot add or remove objects after the array is instantiated. You can, however, retrieve objects from the array. NSArray’s mutable subclass, NSMutableArray, lets you add and remove objects dynamically.
In Objective-C, an array does not actually contain the objects that belong to it; instead it holds a pointer (a reference) to each object. When an object is added to an array,
[array addObject:object];
the address of that object in memory is stored inside the array.
So, to recap, in your command line tool, you created an instance of NSMutableArray and added four instances of NSString to it, as shown in Figure 2.7.
Arrays can only hold references to Objective-C objects. This means primitives and C structures cannot be added to an array. For example, you cannot have an array of ints. Also, because arrays only hold a pointer to an object, a single array can contain objects of different types. This is different from most strongly-typed languages where an array can only hold objects of its declared type.
You can ask an array how many objects it is currently storing by sending it the message count. This information is important because if you ask for an object from an array at an index that is greater than the number of objects in the array, an exception will be thrown. (Exceptions are very bad; they will most likely cause your application to crash. We’ll talk more about exceptions at the end of this chapter.)
int numberOfObjects = [array count];
When an object is added to an array with the message addObject:, it is added at the end of the array. You can also insert objects at a specific index – as long as that index is less than or equal to the current number of objects in the array.
int numberOfObjects = [array count]; [array insertObject:object atIndex:numberOfObjects];
Note that you cannot add nil to an array. If you need to add “holes” to an array, you must use NSNull. NSNull is an object that represents nil and is used specifically for this task.
[array addObject:[NSNull null]];
To retrieve the pointer to an object later, you send the message objectAtIndex: to the array
NSString *object = [array objectAtIndex:0];
For readers who know something about retain counts: an object added to an array is sent the message retain. When an object is removed from an array, it is sent the message release. When an array is deallocated, all of its objects are sent the message release. If you don’t know what retain, release, and deallocate mean, that’s okay; you’ll learn about them in the next chapter.
3.143.5.201