【问题标题】:Objective C print stdout to UIAlertViewObjective C 将标准输出打印到 UIAlertView
【发布时间】:2012-09-01 23:18:06
【问题描述】:

我有一个使用fprintf 打印到标准输出的C 函数,并且我试图在UIAlertView 中显示标准输出的内容。我的代码如下:

NSFileHandle *stdoutFileHandle = [NSFileHandle fileHandleWithStandardOutput];
NSData *stdoutData = [stdoutFileHandle availableData];
NSString *stdoutString = [[NSString alloc] initWithData:stdoutData encoding:NSASCIIStringEncoding];

UIAlertView *stdoutAlert = [[UIAlertView alloc] initWithTitle:@"STDOUT OUTPUT" message:stdoutString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[stdoutAlert show];

我在运行代码时遇到以下错误。

由于未捕获的异常“NSFileHandleOperationException”而终止应用程序,原因:“[NSConcreteFileHandle availableData]:错误的文件描述符”

当我将 [stdoutFileHandle availableData] 替换为 [stdoutFileHandle readDataToEndOfFile] 时,我得到了一个等效的错误。

【问题讨论】:

  • 您真正需要做的是使用select 和一个UNIX 文件描述符。

标签: objective-c ios stdout nsfilehandle


【解决方案1】:

问题是您正在从输出流中读取。要完成这项工作,您需要欺骗 stdout 将其内容写入输入流而不是控制台。

我知道执行此操作的旧 C 方法,但您不会喜欢它。这使用pipe() 和dup2()。

int pipefd[2];

pipe(pipefd);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);

此时,pipefd[0] 可以读取任何写入标准输出的内容。此时您可以使用-initWithFileDescriptor: 读取pipefd[0]

NSFileHandle *stdoutReader = [[NSFileHandle alloc] initWithFileDescriptor:pipefd[0]];

注意,您需要进行大量的错误检查。希望对您有所帮助。

【讨论】:

    【解决方案2】:

    我在这个问题中关注了选定的答案帖子: What is the best way to redirect stdout to NSTextView in Cocoa?

    对我来说感觉有点熟悉。我为管道和读取处理程序创建了一个 NSPipe 和 NSFileHandler 对象,并使用了通知。由于我的需要,我将下面的 open 方法放在 viewDidAppear 和 viewDidDisappear 方法中,但是您可以将其放在合适的位置

    // Piping stdout info from here WILL NOT PIPE NSLOG:
    // https://*.com/questions/2406204/what-is-the-best-way-to-redirect-stdout-to-nstextview-in-cocoa
    - (void) openConsolePipe {
        _pipe = [NSPipe pipe];
        _pipeReadHandle = [_pipe fileHandleForReading] ;
        dup2([[_pipe fileHandleForWriting] fileDescriptor], fileno(stdout)) ;
    
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleNotification:) name: NSFileHandleReadCompletionNotification object: _pipeReadHandle] ;
        [_pipeReadHandle readInBackgroundAndNotify] ;
    }
    
    - (void) closeConsolePipe {
        if (_pipe != nil) {
            [[_pipe fileHandleForWriting] closeFile];
    
            // documentation suggests don't need to close reading file handle b/c auto but this suggests otherwise:
            // https://*.com/questions/13747232/using-nstask-and-nspipe-causes-100-cpu-usage
    //        [[_pipe fileHandleForReading] closeFile];
        }
    }
    
    - (void) handleNotification:(NSNotification *)notification {
        [_pipeReadHandle readInBackgroundAndNotify] ;
        NSString *str = [[NSString alloc] initWithData: [[notification userInfo] objectForKey: NSFileHandleNotificationDataItem] encoding: NSUTF8StringEncoding];
    
        // do what you want with the str here.
        [_consoleView setText:[_consoleView.text stringByAppendingString:str]];
        [_consoleView scrollRangeToVisible:NSMakeRange([_consoleView.text length], 0)];
    }
    

    我希望这最终能帮助其他人在谷歌上搜索...

    【讨论】: