2.8 Operating System Interaction

The Foundation framework provides many services through a small set of classes that allow developers to interact with the underlying operating system in several ways. NSTask is an object-oriented interface to configure and launch a process as a subprocess of the current application. NSProcessInfo lets an application discover information about its current process.

2.8.1 Process Info

Example 2-35 shows some of the information you can obtain by using NSProcessInfo.

Example 2-35. Using NSProcessInfo
// Get the shared process info object for the current process
NSProcessInfo *proc = [NSProcessInfo processInfo];

// The name and PID of the process
NSString *name = [proc processName];
int pid = [proc processIdentifier];

// The arguments launched with the process
NSArray *args = [proc arguments];

// A dictionary of the environment variables for the process
NSDictionary *env = [proc environment];

// The host name for the host running the process
NSString *host = [proc hostName];

// The operating system version string
// Note: this string is NOT appropriate for parsing
NSString *ver = [proc operatingSystemVersionString];

2.8.2 Tasks

NSTask is a class that lets a program configure, launch, and communicate with another program as a subprocess. This is something you'll see every time you execute an application you work on from within Project Builder.

An NSTask is launched in a fully configurable execution environment where environment variables, command line options, and other key points of a task may be set. By default, if no environment configuration is provided for a new task, the task inherits the environment of the parent process that launched it.

Setting up and running a task is straightforward. For example, you could run ls on the root directory, as shown in Example 2-36.

Example 2-36. The quick and dirty NSTask
NSArray *args = [NSArray arrayWithObject:@"/"];
NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/ls

Since no environment was set up for the task, the environment of the parent process is used, which includes sending the standard output of the child process to the standard output of the parent process. The issue of interprocess communication becomes important when working with multiple tasks in an application, since tasks do not share memory space with one another, as do multiple threads of an application. You could improve Example 2-33 so the standard output data can be read from a file handle, rather than being forwarded to the parent processes' standard output. Example 2-37 illustrates the flexibility Cocoa offers for configuring and launching new processes.

Example 2-37. A more complex use of NSTask
NSData *data;

// Instantiate and initialize a new task
NSTask *task = [[NSTask alloc] init];

// Create a pipe to communicate with the task
NSPipe *pipe = [NSPipe pipe];

// Get a file handle to read from the pipe
NSFileHandle *fh = [pipe fileHandleForReading];

// Set the path to launch the task at
[task setLaunchPath:@"/bin/ls"];

// Set the arguments; ls takes the directory to list
[task setArguments:[NSArray arrayWithObject:@"/"]];

// Connect the pipe to the task's stdout
[task setStandardOutput:pipe];

// Finally, launch it
[task launch];

// Once its launched we can read data from the pipe
data = [fh availableData];
NSLog(@"%s", [data bytes]);

If you compile and run this code, you will find the result to be the same as that from Example 2-36. The point of this exercise, however, was to demonstrate how to fine tune a task in every practical manner.

    Part II: API Quick Reference