假设你想写一个函数如同NSLog,除了记录消息之外,它还将消息保存到数组中。你会如何实施这个?
如果你写一个可变参数函数 void MySpecialLog(NSString *format, ...)
,有人可以像 NSLog 一样调用你的函数 -MySpecialLog(@"Hello %@!", name);
- 但访问额外参数的唯一方法format
与a va_list。没有splat操作符在 C 或 Obj-C 中,允许您将它们直接传递给函数内的 NSLog。
NSLogv 通过一次接受所有附加参数来解决这个问题va_list
。它的签名是void NSLogv(NSString *format, va_list args)
。你可以用它来建立你自己的NSLog 包装器。
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);
}
您甚至可以使用相同的技术用 Obj-C 方法包装 NSLog。 (并且自从-[NSString initWithFormat:]
有一个类似的变体称为-initWithFormat:arguments:
,你也可以把它包起来。)
- (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
在 Swift 中,您可以使用接受的可变参数函数来做到这一点CVarArg...
:
func mySpecialLog(_ format: String, _ args: CVarArg...) {
withVaList(args) {
NSLogv("You've called mySpecialLog()! " + format, $0)
}
}