Techniques for printing an NSString to STDOUT

Recently, when developing a CGI program using the ObjectiveCGI class, I found myself in need of a quick way to dump an NSString to STDOUT.

The Foundation APIs provide NSLog(), but NSLog is no good for anything but debugging. First of all, the output is timestamped, and secondly, it goes to STDERR.

After searching around for a bit, I discovered that this particular need was not answered to a satisfactory extent online -- Apple has no Developer Tech Note or documentation on the subject, and what little I could find came from developer mailing lists. As a consequence, I decided to put up this page, demonstrating possible techniques and their advantages/disadvantages.

On-the-fly C string conversion

One method of dumping an NSString to STDOUT is to convert the object to a C string and then use good old fprintf.

#import Foundation/Foundation.h

int main (int argc, char *argv[])
{
     NSString *str = [NSString stringWithString: @"Hello, World"];

     fprintf(stdout, "%s", [myString cString]);

     return 0;
}

While simple to use, this method is flawed. First of all, the cString method is now deprecated in favour of cString: encoding:, which means you'll have text encoding problems, and that's really unpleasant stuff. Secondly, printing a formatted NSString directly is cumbersome and ill-readable, as exemplified by the following example:

printf("%s", [[NSString stringWithFormat: @"%@", str] cString]);

Print NSData to STDOUT filehandle

Another way of dumping a string to STDOUT is to convert the NSString to an NSData object and use the NSFileHandle method writeData:.

#import Foundation/Foundation.h

int main (int argc, char *argv[])
{
     NSFileHandle *stdout = [NSFileHandle fileHandleWithStandardOutput];
     NSString *str = [NSString stringWithString: @"Hello, World"];
     NSData *strData = [str dataUsingEncoding: NSASCIIStringEncoding];

     [stdout writeData: strData];
     return 0;
}

This conversion method should be less error-prone than the C string conversion above. However, it's certainly not elegant, and is too much code for such little functionality.

A superior way: writeToFile

That's right. Remember how everything in UNIX is a file? In my humble opinion, the most beautiful and elegant way to dump an NSString to STDOUT is unquestionably the following:

#import Foundation/Foundation.h

int main (int argc, char *argv[])
{
     NSString *str = [NSString stringWithString: @"Hello, World"];

     // And here comes the magic one-liner
     [str writeToFile:@"/dev/stdout" atomically: NO];

     return 0;
}

Yes, we just write the string to the STDOUT character device. It's short, it's simple and it does exactly what we want it to, without any crusty overhead in terms of objects or lines of code. And if we want even greater convenience, we can just wrap it in a function:

void NSPrint (NSString *str)
{
     [str writeToFile: @"/dev/stdout" atomically: NO];
}

This will allow us to dump out formatted NSStrings quite elegantly, without bracket chaos.

NSPrint([NSString stringWithFormat: @"%@ %@", str1, str2]);

All in all, I think a function like this should be included as part of the Foundation APIs. It is at least as essential for developers to be able to easily dump stuff to STDOUT as it is for them to debug using NSLog().