Что я хочу сделать, это запустить задачу командной строки (CL) (обернутый NSTask) и передать (NSPipe) символьный вывод через метку NSTextField в моем пользовательском интерфейсе в режиме реального времени в виде потока символов.Цель текстового поля - не захватывать вывод каким-либо образом и даже не позволять его читать.Это просто для отображения, частично как украшение пользовательского интерфейса и частично как индикатор прогресса.Я хочу, чтобы пользователь видел поток символов, просто проходящих (быстро), когда задача CL выполняет свою работу.
Я знаю, как обернуть задачу CL в NSTask и получить ее вывод, установив [task setStandardOutput: outputPipe], а затем читать из этого вывода с помощью NSFileHandle.И я думаю, что знаю, как сделать то, что я хочу, «сложным» способом, используя один из методов чтения NSFileHandle и синхронно нарезая выходные данные на куски и отображая эти куски один за другим в текстовом поле.Но я надеюсь, что мог бы быть какой-то легкий способ, которым я не задумывался о том, чтобы перебросить необработанные символы ascii из stdout в текстовое поле в режиме реального времени.
У кого-нибудь есть идея?
РЕДАКТИРОВАТЬ : Вот некоторый рабочий код, основанный на ответе @Peter Hosey.Он делает то, что я хочу, но я не знаю, полностью ли я ухватил концепцию Питера или я делаю здесь что-то нехорошее, поэтому, пожалуйста, не стесняйтесь комментировать.Еще раз спасибо, Питер!
примечания к этому коду:
1) изменение scheduleTimerWithTimeInterval в init с .001 до .005 - интересный визуальный диапазон для эффекта прокрутки текста.
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