2013-05-06 13 views

Odpowiedz

6

Poniższy kod wykorzystuje dup2 podłączyć stdout na koniec zapisu obiektu NSPipe. Read-end jest obserwowany ze źródłem wysyłki GCD, które odczytuje dane z potoku i dołącza je do widoku tekstowego.

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(@"...") nie wyjście do stdout chociaż - Drukuje do stderr. Jeśli chcesz przekierować że w swojej TextView zmień

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

do

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

To może być głupie pytanie, ale: jeśli NSPipe jest już zbuforowane (przez własną implementację lub przez konstrukcję OS, którą się opakowuje), to dlaczego konieczne jest zdefiniowanie własnego bufora danych? – algal

+0

Masz rację NSPipe jest domyślnie buforowana (z dokumentacji "... rura jest buforowana, rozmiar bufora jest określany przez system operacyjny ..."). Ale nadal dobrym pomysłem jest czytanie fragmentów, aby mieć dokładniejszą kontrolę nad zużyciem pamięci w ramach własnego procesu. (Wygląda na to, że bufor rury jest utrzymywany przez system operacyjny). –

+0

Czy jest też możliwe, że pętla 'do' nieprawidłowo testuje błędy lub warunki zakończenia zamiast braku tych warunków? – algal

0

jeśli celem jest, aby obsłużyć tylko swoje wyjście NSLog, a nie system wygenerował dzienników błędów, nie ma innego sposobu, aby zrób tak, tutaj jest kod do przełożenia NSLog. Ten kod jest drukowanie tylko dziennik i kilka dodatkowych informacji na stderr zamiast zwykłego wyjścia NSLog, ale można dokonywać żadnych zmian, które Apartamenty swoich potrzeb wewnątrz funkcji 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); 
} 

następnie wystarczy umieścić te 2 linie na górze dowolnego pliku programu mają działać

#define HYPER_LOG 
#import "HyperLog.h" 

Próbowałem użyć powyższego kodu z Thomasa, aby uzyskać dane wynikowe wygenerowanego przez system dziennika błędów zapisanego w pliku tekstowym za pomocą funkcji C, która działa poprawnie w innych kontekstach, ale zachowuje się i ulega awarii, a błąd powód jest tracony w procesie. Ktoś ma pomysł, dlaczego?