タイトル鶴薗賢吾のCocoaはやっぱり!出張版》7. UNIXコマンドの実行(2)カテゴリーCocoa, 鶴薗賢吾のCocoaはやっぱり!出張版
作成日2002/1/22 1:57:19作成者新居雅行
――――MoriarityControllerの詳細
では、詳細の説明に入っていきます。ユーザーがSleuthボタンをクリックすると実行されるsleuth : メソッドからです。

// ソース:MoriarityController.m/メソッド:sleuth

- (IBAction) sleuth : (id) sender {

if ( findRunning ) { // コマンド実行中
[ searchTask stopProcess ]; // 実行中止
: 省略
}
else { // コマンド未実行時
: 省略
searchTask = [ [ TaskWrapper alloc ]
initWithController : self
arguments : [ NSArray arrayWithObjects :
@"/usr/bin/locate",
[ findTextField stringValue ],
nil ] ]; // 初期化
[ searchTask startProcess ]; // コマンド実行
}
}

コマンドが既に実行されている場合は、TaskWrapperのコマンド実行を止めるstopProcessメソッドを呼んだり、その他の終了処理を行います。実行されていない場合は、TaskWrapperクラスのインスタンスであるsearchTaskを生成します。allocした後、initWithController : arguments : メソッドを呼んで初期化します。このメソッドでコントローラとUNIXコマンドとパラメータを指定できます。コントローラは自分自身ですのでselfを渡します。パラメータは、配列で渡しますが、最初の要素は実行するコマンドのパスで、それ以降がコマンドのパラメータになっています。そして、startProcessメソッドを呼ぶことでUNIXコマンドが実行されます。stopProcessとstartPorcessについては、後程説明します。

startProcessメソッドを呼ぶと、searchTaskからコントローラ側の初期化としてのprocessStartedメソッドが呼び返されます。結果を表示するテキストフィールドをクリアしたり、Sleuthボタンのタイトルを変更したりします。

// ソース:MoriarityController.m/メソッド:processStarted

- (void) processStarted {
findRunning = YES;
[ resultsTextField setString : @"" ]; // テキストフィールドのクリア
[ sleuthButton setTitle : @"Stop" ]; // Sleuthボタンのタイトル変更
}

その後、UNIXコマンドが実行開始されます。UNIXコマンドから結果が出力されると、TaskWrapperからappendOutput : メソッドが呼ばれます。このメソッドは、繰り返し呼ばれます。NSTextViewにテキストを追加してスクロールする処理を行っています。

// ソース:MoriarityController.m/メソッド:appendOutput

- (void) appendOutput : (NSString *) output {

[ [ resultsTextField textStorage ]
appendAttributedString : [ [ [ NSAttributedString alloc ]
initWithString : output ] autorelease ] ];
[ self performSelector : @selector(scrollToVisible:)
withObject : nil
afterDelay : 0.0 ];
}

- (void) scrollToVisible : (id) ignore {
[ resultsTextField scrollRangeToVisible :
NSMakeRange( [ [ resultsTextField string ] length ], 0 ) ];
}

コマンド実行が終了したら、TaskWrapperからprocessFinishedメソッドが呼ばれます。ここでSleuthボタンのタイトルを元に戻したりしています。

// ソース:MoriarityController.m/メソッド:processFinished

- (void) processFinished {
findRunning = NO;
[ sleuthButton setTitle : @"Sleuth" ]; // Sleuthボタンのタイトル変更
}

――――TaskWrapperの詳細
ここからは、TaskWrapperクラスの詳細について説明を行います。TaskWrapperは、FoundationフレームワークのNSTaskというUNIXのコマンドを呼び出すクラスと直接やり取りを行うクラスですので、ここからが本題となります。

◎ コマンドの実行まで
まずは、TaskWrapperの初期化メソッドである initWithController : arguments : からです。このメソッドはallocされた直後に呼ばれます。やりとりを行うコントローラのインスタンスと、コマンドのパスとパラメータを配列で受け取って記憶します。

// ソース:MoriarityController.m/メソッド:initWithController

- (id) initWithController : (id <TaskWrapperController>) cont
arguments : (NSArray *) args {
self = [ super init ]; // スーパークラスによる初期化
controller = cont; // コントローラを記憶
arguments = [ args retain ];
// コマンドとコマンドに渡すパラメータを記憶
return self;
}

次は、実際にコマンドを実行するstartProcessメソッドです。ちょっと長くなりますが、まずは全体を見てください。最初のところでは、先程説明しましたprocessStartedというコントローラを初期化するメソッドを実行しています。

// ソース:MoriarityController.m/メソッド:startProcess

- (void) startProcess {

[ controller processStarted ]; // コントローラの初期化

// 実行準備
task = [ [ NSTask alloc ] init ]; // 生成と初期化
[ task setStandardOutput : [ NSPipe pipe ] ]; // 標準出力変更
[ task setStandardError : [ task standardOutput ] ]; // 標準エラー変更
[ task setLaunchPath : [ arguments objectAtIndex : 0 ] ];
// コマンド設定
[ task setArguments : [ arguments subarrayWithRange :
NSMakeRange( 1, ([arguments count] - 1) ) ] ];
// パラメータ設定
// 標準出力からのデータを受け取るための通知設定
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @selector(getData:)
name : NSFileHandleReadCompletionNotification
object : [ [ task standardOutput ] fileHandleForReading ] ];

[ [ [ task standardOutput ] fileHandleForReading ]
readInBackgroundAndNotify ];

[ task launch ]; // コマンド実行

}

(この項続く)
[鶴薗賢吾]
関連リンクCocoaはやっぱり!