2013-05-06 82 views

回答

6

下面的代碼使用dup2到stdout堵塞到一個NSPipe對象的寫入端。讀端由一個GCD調度源來觀察,它從管道讀取數據並將其附加到文本視圖。

NSPipe* pipe = [NSPipe pipe]; 
NSFileHandle* pipeReadHandle = [pipe fileHandleForReading]; 
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout)); 
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)); 

dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stderr)); 
+0

這可能是一個愚蠢的問題,但是:如果NSPipe已經被緩衝了(通過它自己的實現或者由它包裝的OS構造),那麼爲什麼需要定義自己的數據緩衝區? – algal 2015-12-08 00:33:54

+0

你是對的NSPipe默認被緩衝(來自文檔「...管道被緩衝;緩衝區的大小由底層操作系統決定......」)。但是,在分塊讀取時,可能還是一個好主意,以便在您自己的進程中更好地控制內存消耗。 (聽起來像管道的緩衝區由操作系統維護) – 2015-12-09 08:35:16

+0

另外,是否有可能'do'循環錯誤地測試錯誤或終止條件,而不是缺少這些條件? – algal 2015-12-09 17:04:04

0

如果目標是隻能處理您的NSLog輸出,而不是生成系統錯誤日誌,有一個其他的方式來這樣做,這是一個代碼來覆蓋NSLog。此代碼只打印日誌和標準錯誤,而不是通常的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, ...); 

Hyperlog .M

#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); 
} 

然後你只需把這些2行上的任何程序文件的頂部 有它的工作

#define HYPER_LOG 
#import "HyperLog.h" 

我試圖使用托馬斯的上述代碼將系統的結果數據生成的錯誤日誌寫入使用C函數的文本文件,該函數在其他上下文中正常工作,但它保持並崩潰,並且錯誤在這個過程中失去了理智。任何人有一個想法爲什麼?

相關問題