Objective c 如何将STDOUT重定向到NSTextView?

Objective c 如何将STDOUT重定向到NSTextView?,objective-c,macos,cocoa,stdout,Objective C,Macos,Cocoa,Stdout,有人能告诉我如何将Stdout重定向到NSTextView吗 NSLog打印的信息是否属于std 感谢下面的代码使用dup2将标准输出插入NSPipe对象的写入端。读取端由GCD调度源观察,该源从管道读取数据并将其附加到textview NSPipe* pipe = [NSPipe pipe]; NSFileHandle* pipeReadHandle = [pipe fileHandleForReading]; dup2([[pipe fileHandleForWriting] fileDes

有人能告诉我如何将Stdout重定向到NSTextView吗

NSLog打印的信息是否属于std


感谢下面的代码使用
dup2
将标准输出插入
NSPipe
对象的写入端。读取端由GCD调度源观察,该源从管道读取数据并将其附加到textview

NSPipe* pipe = [NSPipe pipe];
NSFileHandle* pipeReadHandle = [pipe fileHandleForReading];
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout));
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [pipeReadHandle fileDescriptor], 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(source, ^{
    void* data = malloc(4096);
    ssize_t readResult = 0;
    do
    {
        errno = 0;
        readResult = read([pipeReadHandle fileDescriptor], data, 4096);
    } while (readResult == -1 && errno == EINTR);
    if (readResult > 0)
    {
        //AppKit UI should only be updated from the main thread
        dispatch_async(dispatch_get_main_queue(),^{
            NSString* stdOutString = [[NSString alloc] initWithBytesNoCopy:data length:readResult encoding:NSUTF8StringEncoding freeWhenDone:YES];
            NSAttributedString* stdOutAttributedString = [[NSAttributedString alloc] initWithString:stdOutString];
            [self.logView.textStorage appendAttributedString:stdOutAttributedString];
        });
    }
    else{free(data);}
});
dispatch_resume(source);
NSLog(@“…”)
不会输出到
stdout
但是-它会打印到
stderr
。如果要将其重定向到textview,请更改

dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout));


如果目标是只处理NSLog输出,而不是系统生成的错误日志,那么还有另一种方法,下面是对NSLog进行超类的代码。这段代码只是在stderr上打印日志和一些额外的信息,而不是通常的NSLog输出,但是您可以在HyperLog函数中根据需要进行任何更改:

HyperLog.h

#import <Foundation/Foundation.h>

#ifdef HYPER_LOG
#define NSLog(args...) HyperLog(__FILE__,__LINE__,__PRETTY_FUNCTION__,args);
#else
#define NSLog(x...)
#endif

void HyperLog(const char *file, int lineNumber, const char *functionName, NSString *format, ...);

我尝试使用Thomas提供的上述代码,使用C函数将系统生成的错误日志的结果数据写入到文本文件中,该函数在其他上下文中正常工作,但它会继续运行并崩溃,错误原因在过程中丢失。有人知道为什么吗?

我知道这个问题是关于objective-c的,但我想我会发布一个快速的答案,以帮助其他人

let pipefd = UnsafeMutablePointer<Int32>.allocate(capacity: 8)
pipe(pipefd)

dup2(pipefd[1], fileno(stdout))

// Print something here

let buf = UnsafeMutableRawPointer.allocate(byteCount: 1024, alignment: 0)
read(pipefd[0], buf, 100)

close(pipefd[1])

let output = self.ptrToString(pointer: buf)
if output != "" {
    // Do something with output
}

buf.deallocate()
pipefd.deallocate()

适用于swift 4

这可能是一个愚蠢的问题,但是:如果NSPipe已经被缓冲(通过其自身的实现或其包装的OS构造),那么为什么有必要定义您自己的数据缓冲区?您是对的,NSPipe在默认情况下被缓冲(从文档中)“…管道是缓冲的;缓冲区的大小由底层操作系统决定…”。但是分块读取仍然是一个好主意,以便在您自己的进程中对内存消耗进行更细粒度的控制。(听起来管道的缓冲区是由操作系统维护的)另外,
do
循环是否可能错误地测试错误或终止条件,而不是没有这些条件?while循环不控制对可用数据的迭代。它只处理发送中断信号的极不可能的情况。调度源处理程序被多次调用en可用数据大于缓冲区大小。由于NSPipe、NSFileHandle和dup2在iOS中可用…我们可以放心地认为它也适用于iOS!
#import "HyperLog.h"

void HyperLog(const char *file, int lineNumber, const char *functionName, NSString *format, ...)
{
    va_list ap;
    va_start (ap, format);
    if (![format hasSuffix: @"\n"])
    {
        format = [format stringByAppendingString: @"\n"];
    }

    NSString *body = [[NSString alloc] initWithFormat:format arguments:ap];
    va_end (ap);
     NSString *fileName = [[NSString stringWithUTF8String:file] lastPathComponent];
    char mesg[8192]="\0";
    NSDate *now =[NSDate date];
    NSString *dateString = [NSDateFormatter localizedStringFromDate:now dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterMediumStyle];
    if ( sprintf( mesg, "<%s.%03.0f> : %s\n<%s : %d - %s>\n", [dateString UTF8String],roundf(fmod( [now timeIntervalSinceReferenceDate], 1 ) * 1000), [body UTF8String], [fileName UTF8String],
                 lineNumber,
            functionName) < 0 ) printf("message creation failed\n");
    fprintf(stderr, "%s", mesg );
}
#define HYPER_LOG
#import "HyperLog.h"
let pipefd = UnsafeMutablePointer<Int32>.allocate(capacity: 8)
pipe(pipefd)

dup2(pipefd[1], fileno(stdout))

// Print something here

let buf = UnsafeMutableRawPointer.allocate(byteCount: 1024, alignment: 0)
read(pipefd[0], buf, 100)

close(pipefd[1])

let output = self.ptrToString(pointer: buf)
if output != "" {
    // Do something with output
}

buf.deallocate()
pipefd.deallocate()
func ptrToString (pointer buf: UnsafeMutableRawPointer) -> String {
    let filteredArray = Array(UnsafeBufferPointer(start: buf.assumingMemoryBound(to: UInt8.self), count: 1024)).filter { item in
        return item != 0
    }

    return filteredArray
        .map { String(UnicodeScalar(UInt8($0))) }
        .joined()
        .components(separatedBy: "\n")[0]
}