我想要實現的是通過我的UI中的NSTextField標籤啓動命令行(CL)任務(包裝NSTask)和管道(NSPipe)字符輸出,時間就像一串人物。文本字段的目的不是以任何方式捕獲輸出,甚至不允許讀取它。這只是爲了展示它,部分作爲用戶界面的裝飾,部分作爲一種進度指標。我希望用戶在CL任務完成其工作時看到流(快)的字符流。NSTask字符輸出到NSTextField緩衝爲連續流
我知道如何將CL任務包裝到NSTask中,並通過設置[task setStandardOutput:outputPipe]來獲得輸出,然後使用NSFileHandle從該輸出中讀取。我想我知道如何使用NSFileHandle讀取方法之一來實現我想要的「硬」方式,同時將輸出切分爲塊並在文本字段中逐個顯示這些塊。但我希望可能有一些輕量級的方式,我沒有想過要將標準輸出中的原始ASCII字符實時地傳送到文本字段中。
任何人有想法?
編輯:這是一些基於@Peter Hosey的答案的工作代碼。它正在做我想做的事情,但我不知道我是否徹底改變了彼得的概念,或者如果我在這裏做了任何蠢事,請隨時發表評論。再次感謝彼得!在此代碼
筆記:
1)改變scheduledTimerWithTimeInterval在從0.001到0.005的INIT是一個有趣的視覺範圍的文本滾動效果。
2)我使用的標籤只是一個簡單的文本標籤,在我的界面構建器的用戶界面上創建。爲了我的目的,我不需要用正確的屬性字符串來做彼得答案的第二部分。我只是在界面生成器中設置文本標籤的理由。
@interface MyWrapper : NSObject
@property (assign) NSMutableData *_outputData;
@property (assign) NSFileHandle *_fileHandle;
@property (assign) IBOutlet NSTextField *label;
@property (assign) NSTimer *_timer;
-(void) readData:(NSNotification *)notification;
-(void) displayOutput;
-(void) doIt;
@end
@implementation MyWrapper
@synthesize _outputData, _fileHandle, label, _timer;
- (id)init {
self = [super init];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(readData:)
name:NSFileHandleReadCompletionNotification
object:nil];
_outputData = [[NSMutableData alloc] initWithCapacity:300];
_timer = [NSTimer scheduledTimerWithTimeInterval:.001
target:self
selector:@selector(displayOutput)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_timer invalidate];
[super dealloc];
}
-(void) readData:(NSNotification *)notification {
if([notification object] != _fileHandle)
return;
[_outputData appendData:[[notification userInfo]
objectForKey:NSFileHandleNotificationDataItem]];
[_fileHandle readInBackgroundAndNotify];
}
-(void) displayOutput {
if ([_outputData length] == 0) {
return;
}
NSString *labelText = [label stringValue];
NSData *nextByte;
NSString *nextChar;
// pull first character off of the outputData
nextByte = [_outputData subdataWithRange:NSMakeRange(0, 1)];
nextChar = [[NSString alloc]initWithData:nextByte
encoding:NSASCIIStringEncoding];
// get rid of first byte of data
[_outputData replaceBytesInRange:NSMakeRange(0, 1) withBytes:NULL length:0];
if (! [nextChar isEqualToString:@"\n"]) {
if ([labelText length] > 29) {
labelText = [labelText substringFromIndex:1];
}
labelText = [labelText stringByAppendingString:nextChar];
[label setStringValue:labelText];
}
}
-(void)doIt {
NSTask *theTask = [[NSTask alloc] init];
NSPipe *outPipe =[NSPipe pipe];
//write output to outputData in background
_fileHandle = [outPipe fileHandleForReading];
[_fileHandle readInBackgroundAndNotify];
[theTask setLaunchPath:@"path/to/executable"];
[theTask setStandardOutput:outPipe];
[theTask setStandardError:[NSPipe pipe]];
[theTask launch];
[theTask waitUntilExit];
}
@end
[wrinkled brow]你是說使用定時器週期性地添加新字節,並從NSMutableData中刪除舊字節,然後在文本字段中重新顯示NSMutableData?我在想如何連接所有這些方面掙扎着,但我會試一試並用一些代碼報告。感謝您花時間回覆。 – pjv
@pjv:差不多。您將字節添加到NSMutableData以響應來自文件句柄的通知;您可以根據定時器觸發修剪和更新文本字段。 –