Logging Information
Now that you’ve read the basics about classes and objects, it’s important to understand how to log information about them. In addition to printf, Objective-C offers a fundamental logging function called NSLog. This function works like printf and uses a similar format string, but it outputs to stderr instead of stdout. NSLog also uses an NSString format string rather than a C string one.
NSStrings are declared differently than C strings. They are prepended with the @ (at) symbol. A typical NSString looks @"like this"; the equivalent C string looks "like this" (omitting the @). Whereas C strings refer to a pointer to a string of bytes, NSStrings are objects. You can manipulate a C string by changing the values stored in each byte. NSStrings are immutable; you cannot access the bytes to edit them, and the actual string data is not stored within the object.
// This is 12 bytes of addressable memory printf("%d\n", sizeof("Hello World")); // This 4-byte object points to non-addressable memory NSString *string = @"Hello World"; printf("%d\n", sizeof(*string));
In addition to using the standard C format specifiers, NSLog introduces an object specifier (%@) that lets you print objects. It does so by sending an object the description message. It is then the object’s job to return a human-readable description of itself. This behavior allows you to transform
printf("Make: %s\n", [make UTF8String]);
into
NSLog(@"Make: %@", make);
Table 3-1 shows some of the most common format specifiers. This is far from an exhaustive list, so consult Apple’s String Programming Guide for Cocoa for more details.
Table 3-1. Common String Format Specifiers
Specifier |
Meaning |
%@ |
Objective-C object using the description or description-WithLocale: results |
%% |
The "%" literal character |
%d |
Signed integer (32-bit) |
%u |
Unsigned integer (32-bit) |
%f |
Floating-point (64-bit) |
%e |
Floating-point printed using exponential (scientific) notation (64-bit) |
%c |
Unsigned char (8-bit) |
%C |
Unicode char (16-bit) |
%s |
Null-terminated char array (string, 8-bit) |
%S |
Null-terminated Unicode char array (16-bit) |
%p |
Pointer address using lowercase hex output, with a leading 0x |
%x |
Lowercase unsigned hex (32-bit) |
%X |
Uppercase unsigned hex (32-bit) |
Notice that NSLog does not require a hard-coded return character. It automatically appends a new line when used. What’s more, it adds a timestamp to every log, so the results of the NSLog invocation shown previously look something like this:
2009-05-07 14:19:08.792 HelloWorld[11197:20b] Make: Ford
Nearly every object converts itself into a string via the description message. NSLog uses description to show the contents of objects formatted with %@. This returns an NSString with a textual description of the receiver object. You can describe objects outside of NSLog by sending them the same description method. This is particularly handy for use with printf and fprintf, which cannot otherwise print objects.
fprintf(stderr, "%s\n", [[myCar description] UTF8String]);
Another useful logging function is CFShow(). It takes one argument, an object, and prints out a snapshot description of that object to stderr:
CFShow(make);
Like NSLog, CFShow sends description to the objects it displays. Unlike NSLog, however, CFShow does not clutter your debugging console with timestamps, so it appeals to anyone who prefers to skip that extra information. CFShow doesn’t require format strings, which simplifies adding them to code, but they can only be used with objects. You cannot CFShow an integer or float.
You can combine NSLog’s object-formatting features with printf’s no-prefix presentation by implementing a simple NS-styled print utility such as the following function. This function automatically adds a carriage return, as NSLog does but printf does not. Adjust this accordingly for your own needs.
void nsprintf(NSString *formatString,...) { va_list arglist; if (formatString) { va_start(arglist, formatString); { NSString *outstring = [[NSString alloc] initWithFormat:formatString arguments:arglist]; fprintf(stderr, "%s\n", [outstring UTF8String]); [outstring release]; } va_end(arglist); } }