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.
Example 2-35 shows some of the information you can obtain by 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];
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.
NSArray *args = [NSArray arrayWithObject:@"/"]; NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/ls arguments:args];
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.
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.