タイトル鶴薗賢吾のCocoaはやっぱり!出張版》7. UNIXコマンドの実行(1)カテゴリーCocoa, 鶴薗賢吾のCocoaはやっぱり!出張版
作成日2002/1/22 1:56:45作成者新居雅行
――――今回のテーマ
今回のテーマは、UNIXコマンドの実行です。AppleのサイトにあるサンプルプログラムのMoriarityの説明をしながら、CocoaアプリケーションからUNIXコマンドを実行する方法について解説を行っていきます。このサンプルは、Appleサイト内の以下のURLにありますので、まずはダウンロードしておいてください。

◇Moriarity
 http://developer.apple.com/samplecode/Sample_Code/Cocoa/Moriarity.htm

この解説は、以下の環境を前提にしていますので、ご確認ください。

  • Mac OS X 10.1以降
  • Project Builder 1.1.1 ( December 2001 Developer Tools ) 以降
  • Interface Builder 2.2 ( December 2001 Developer Tools ) 以降

――――アプリケーション概要
このMoriarityというアプリケーションは、以下のような画面になっています。

◇アプリケーションの実行画面
 

Find : の右側に文字列を入力してSleuthボタンをクリックすると、入力した文字列を含むパスが中央のNSTextViewに表示されます。

見た目は、普通のアプリケーションですが、内部ではUNIXのlocate ( /usr/bin/locate ) というコマンドを実行しています。コマンドのパラメータをウィンドウ上部のNSTextFieldから取り出して渡して、コマンドの実行結果をウィンドウ中央のNSTextViewに表示しています。実際に、Terminalアプリケーションで同じことをやってみた結果が以下の図です。コマンドラインから " locate ATIRagePro " とタイプしています。

◇Terminalアプリケーションでの実行画面
 

このようにCocoaアプリケーションからはUNIXのコマンドを実行することができるのです。

ちょっと補足:Moriarityというのは、シャーロック・ホームズに出てくる「モリアリティ教授」の名前から取ったもののようです。また、Sleuthというのは「探偵として働く」という意味です。親友である「ワトソン博士」の名前も後から出てきます。

――――プロジェクトとモジュールの構成
プロジェクトファイルをProject Builderで開いて、プロジェクトを構成するファイルを確認してみましょう。

◇プロジェクトの構成ファイル
 

TaskWrapper.m / TaskWrapper.hというのが、UNIXのコマンドとのやり取りを行うTaskWrapperクラスを定義しているファイルです。CocoaのFoundationフレームワークにはNSTaskというUNIXコマンドを実行するためのクラスがありますが、これをさらに簡単に使えるようにするためのクラスがTaskWrapperです。

MoriarityController.m / MoriarityController.hというのが、ウィンドウとTaskWrapperの仲介役になるMoriarityControllerクラスを定義しているファイルです。ユーザーが入力した内容をアウトレットのfindTextFieldから取り出してTaskWrapperに渡して起動し、また、TaskWrapperからの実行結果をアウトレットのresultsTextFieldに書き込むという仕事を行います。

これらのモジュールの関係を図にしてみました。

◇モジュールの関係図
 

簡単に処理の流れを追ってみます。まず、ユーザーがSleuthボタンをクリックします。すると、TaskWrapperControllerのsleuth : メソッドが実行されます…1。そして、TaskWrapperを初期化して…2、コマンドの実行を指示します…3。そうすると、TaskWrapperはMoriarityControllerに対して出力先の初期化 ( このサンプルではテキストフィールドのクリア ) を行って…4、UNIXコマンドを実行開始します。得られた結果を随時MoriarityControllerに渡して画面に表示させます…5。コマンド実行が終了したら終了処理を行います…6。

このサンプルは、MVC ( Model - View - Controller ) の設計になっていて、ウィンドウがView、MoriarityControllerがController、TaskWrapperがModelになっています。うまく作れば、ModelであるTaskWrapperに変更を加えることなく、ファイルからパラメータを読み込んで、結果をファイルに出力するというような別のアプリケーションに作り替えることが出来ます。

次に、プロジェクトウィンドウのResourcesの中にあるMainMenu.nibをダブルクリックして開いてみましょう。Interface Builderで見ると以下のようになっています ( ウィンドウは小さくしてあります )。WatsonControllerというのがMoriarityControllerのインスタンスになっています。

◇MainMenu.nibの中身
 

TaskWrapperのインスタンスはありませんが、WatsonController ( MoriarityController ) の中に含まれています。MoriarityController.hを見てみると以下のようになっています。searchTaskというのがそれです。

// ソース:MoriarityController.h/@interface MoriarityController

@interface MoriarityController : NSObject <TaskWrapperController>
{
IBOutlet id findTextField;
IBOutlet id resultsTextField;
 : 省略
BOOL findRunning; // 現在実行中
TaskWrapper *searchTask; // タスクラッパー
}
- (IBAction) sleuth : (id) sender; // アクションメソッド
 : 省略
@end

このヘッダーからMoriarityControllerは、TaskWrapperControllerプロトコルを持っていることが分かります。TaskWrapperは、コントローラを制御して出力等を行いますので、コントローラに必要なインターフェイス ( Objective-Cでいうところのプロトコル ) をTaskWrapperControllerとして定義していて、それをMoriarityControllerが持っています。

// ソース:TaskWrapper.h/@protocol TaskWrapperController

@protocol TaskWrapperController
- (void) appendOutput : (NSString *) output; // 結果の出力
- (void) processStarted; // 初期化
- (void) processFinished; // 終了処理
@end

続いてTaskWrapperのヘッダーも見てみましょう。

// ソース:TaskWrapper.h/@protocol TaskWrapperController

@interface TaskWrapper : NSObject
{
NSTask *task; // 実行するコマンド
id <TaskWrapperController> controller; // コントローラ
NSArray *arguments; // コマンドのパラメータ
}
- (id) initWithController : (id <TaskWrapperController>) controller
arguments : (NSArray *) args; // 初期化
- (void) startProcess; // コマンド実行開始
- (void) stopProcess; // コマンド実行中止
@end

taskにはNSTaskのインスタンス記憶し、argumentsにはコマンド実行のためのパラメータを記憶しています。出力をコントローラに任せるために、コントローラのインスタンスもcontrollerに記憶しています。
(この項続く)
[鶴薗賢吾]
関連リンクCocoaはやっぱり!