2016-12-05 5 views

Antwort

7

Angenommen, Sie möchten eine Funktion schreiben ähnlich wie NSLog, aber die speichert die Nachricht in einem Array zusätzlich zur Protokollierung. Wie würdest du das umsetzen?

Wenn Sie schreiben eine variadic functionvoid MySpecialLog(NSString *format, ...), jemand Ihre Funktion wie NSLog nennen kann - MySpecialLog(@"Hello %@!", name); - aber der einzige Weg, mit a va_list die zusätzlichen Argumente jenseits format ist zuzugreifen. Es gibt keine splat operator in C oder Obj-C, so dass Sie sie direkt an NSLog innerhalb der Funktion übergeben können.

NSLogv löst dieses Problem, indem es alle zusätzlichen Argumente auf einmal über eine va_list akzeptiert. Seine Signatur ist void NSLogv(NSString *format, va_list args). Sie können es verwenden bauen Sie Ihre eigenen NSLog Wrapper.

Obj-C

void MySpecialLog(NSString *format, ...) 
    NS_FORMAT_FUNCTION(1, 2) 
    // The NS_FORMAT_FUNCTION attribute tells the compiler to treat the 1st argument like 
    // a format string, with values starting from the 2nd argument. This way, you'll 
    // get the proper warnings if format specifiers and arguments don't match. 
{ 
    va_list args; 
    va_start(args, format); 

    // Do something slightly more interesting than just passing format & args through... 
    NSString *newFormat = [@"You've called MySpecialLog()! " stringByAppendingString:format]; 

    NSLogv(newFormat, args); 

    va_end(args); 
} 

Sie können sogar die gleiche Technik verwenden NSLog mit einer Obj-C-Methode zu wickeln. (Und da -[NSString initWithFormat:] eine ähnliche Variante hat -initWithFormat:arguments: genannt, können Sie es wickeln.)

- (void)log:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2) 
{ 
    // Similarly to the above, we can pass all the arguments to -initWithFormat:arguments:. 
    va_list args; 
    va_start(args, format); 
    NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; 
    va_end(args); 

    // Why not both? 
    va_start(args, format); 
    NSLogv(format, args); 
    va_end(args); 
} 

Swift

In Swift, können Sie dies mit einer variadische Funktion akzeptieren CVarArg...:

func mySpecialLog(_ format: String, _ args: CVarArg...) { 
    withVaList(args) { 
     NSLogv("You've called mySpecialLog()! " + format, $0) 
    } 
} 
+0

Ja, aber ich habe nicht den Punkt bekommen ... das, warum wir nslogv und seinen Zweck verwenden müssen – Sivagami

+0

Sollte es nicht sein * ...Wenn Sie NSLog nicht haben, ... "* in der ersten Zeile Ihres ersten Codebeispiels? –

+0

Nein. Der Punkt ist zu veranschaulichen, dass NSLogv notwendig ist. – jtbandes

1

Im Allgemeinen bedeutet ein Suffix von v, dass eine Funktion ein va_list als Argument anstelle einer variadischen Argumentliste verwendet.

Dies ist der Fall für NSLog und NSLogv:

void NSLog(NSString *format, ...); 

void NSLogv(NSString *format, va_list args); 

Dies ist nützlich, in ganz bestimmten Situationen, in denen Sie benötigen, um „wrap“ eine Funktion, die variadische Argumente annimmt. Wenn Sie es brauchen, werden Sie es wissen. Andernfalls können Sie es ignorieren.

+0

Bitte erklären Sie "Sie müssen" "eine Funktion, die variadic Argumente übernimmt" wrapping –

1

NSLog ist ein varadic function, was bedeutet, dass es eine variable Anzahl von Argumenten benötigt. Aber manchmal wollen Programmierer ihre eigene varadische Wrapper-Funktion implementieren, die etwas anderes vor dem Aufruf von NSLog ausführt.

Wenn die einzige Funktion wäre, wäre das nicht möglich, weil Sie eine Gruppe von Varadic-Argumenten (aka va_list) nicht an eine andere varadic-Funktion übergeben können.

Deshalb NSLogv existiert separat von NSLog, das ist nur ein Wrapper, der eine variable Anzahl von Argumenten akzeptiert und übergibt sie an NSLogv.