Difference between NSLog and NSLogv
Asked Answered
F

3

7

Can anyone explain the difference between NSLog and NSLogv? I know NSLog is used to print data in the console. But what is NSLogv?

Fraley answered 5/12, 2016 at 6:19 Comment(0)
C
16

Suppose you want to write a function similar to NSLog, but which also saves the message to an array in addition to logging it. How would you implement this?

If you write a variadic function void MySpecialLog(NSString *format, ...), someone can call your function just like NSLog — MySpecialLog(@"Hello %@!", name); — but the only way to access the extra arguments beyond format is with a va_list. There's no splat operator in C or Obj-C allowing you to pass them directly to NSLog inside the function.

NSLogv solves this problem by accepting all the additional arguments at once via a va_list. Its signature is void NSLogv(NSString *format, va_list args). You can use it to build your own NSLog wrappers.

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

You can even use the same technique to wrap NSLog with an Obj-C method. (And since -[NSString initWithFormat:] has a similar variant called -initWithFormat:arguments:, you can wrap it too.)

- (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, you can do this with a variadic function accepting CVarArg...:

func mySpecialLog(_ format: String, _ args: CVarArg...) {
    withVaList(args) {
        NSLogv("You've called mySpecialLog()! " + format, $0)
    }
}
Cropland answered 5/12, 2016 at 6:33 Comment(2)
Shouldn't it be "... if you didn't have NSLog, ..." in the first line of your first code example?Brother
@jtbandes: Exactly. You build a NSLog replacement using NSLogv, therefore "if you didn't have NSLogv" sounds misleading to me.Brother
P
2

Generally speaking, a suffix of v means that a function takes a va_list as an argument, instead of a variadic argument list.

This is the case for NSLog and NSLogv:

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

void NSLogv(NSString *format, va_list args);

This is useful in certain very specific situations where you need to "wrap" a function that takes variadic arguments. If you need it, you'll know. Otherwise, you can safely ignore it.

Prater answered 5/12, 2016 at 6:32 Comment(1)
Please explain "you need to "wrap" a function that takes variadic arguments"Hanks
D
1

NSLog is a varadic function, which means it takes a variable number of arguments. But sometimes, programmers will want to implement their own varadic wrapper function which does something else before calling NSLog.

If NSLog was the only function, that wouldn't be possible because you can't pass a set of varadic arguments (aka a va_list) to another varadic function.

That's why NSLogv exists separately from NSLog, which is just a wrapper that accepts a variable number of arguments and passes them to NSLogv.

Ducks answered 5/12, 2016 at 6:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.