gpt4 book ai didi

objective-c - NSTask 字符输出到 NSTextField 无缓冲作为连续流

转载 作者:行者123 更新时间:2023-12-03 16:33:04 26 4
gpt4 key购买 nike

我想要完成的是启动命令行(CL)任务(包装的 NSTask)并通过 UI 中的 NSTextField 标签以字符流的形式实时传输字符输出(NSPipe)。文本字段的目的不是以任何方式捕获输出,甚至不允许读取输出。它只是为了显示它,部分作为 UI 装饰,部分作为一种进度指示器。我希望用户在 CL 任务完成工作时看到一串字符(快速)流过。

我知道如何将 CL 任务包装在 NSTask 中,并通过设置 [task setStandardOutput:outputPipe] 获取其输出,然后使用 NSFileHandle 从该输出中读取。我想我知道如何使用 NSFileHandle 读取方法之一以“硬”方式做我想要的事情,并同步将输出切成 block 并在文本字段中一一显示这些 block 。但我希望可能有一些我没有想到的轻量级方法可以将原始 ASCII 字符从标准输出实时发送到文本字段。

有人有想法吗?

编辑:这是一些基于@Peter Hosey 答案的工作代码。它正在做我想做的事情,但我不知道我是否彻底理解了彼得的概念,或者我是否在这里做了任何奇怪的事情,所以请随意发表评论。再次感谢彼得!

此代码的注释:

1) 将 init 中的 ScheduledTimerWithTimeInterval 从 .001 更改为 .005 对于文本滚动效果来说是一个有趣的视觉范围。

2) 我使用的标签只是在界面生成器中的 UI 上创建的简单文本标签。出于我的目的,我不需要使用正确的合理属性字符串来完成彼得答案的第二部分。我只是在界面生成器中设置了文本标签的对齐方式。

@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

最佳答案

Asynchronous reading of the file handle ,一个timer ,一个 NSMutableData,您可以通过仅保留最后一个字节并删除旧字节来将其限制为固定字节数(假设为 300),并在文本字段中右对齐。

对于最后一部分,您需要制作 the default paragraph style 的可变副本, set its alignmentright justification ,并设置文本字段的 attributed string value段落样式为 one of its attributes 的属性字符串.

关于objective-c - NSTask 字符输出到 NSTextField 无缓冲作为连续流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6635086/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com