你如何从Swift中调用Objective-C的可变参数?

假设我在Objective-c中有一个类,像这样的静态方法:

+ (NSError *)executeUpdateQuery:(NSString *)query, ...; 

我如何从Swift中调用? 自动完成不能识别它,编译器不满意:

 MyClassName.executeUpdateQuery("") 

抱怨'MyClassName.Type没有名为executeUpdateQuery的成员'

写一个可变参数方法的va_list版本;

 + (NSError *)executeUpdateQuery:(NSString *)query, ... { va_list argp; va_start(argp, query); NSError *error = [MyClassName executeUpdateQuery: query args:argp]; va_end(argp); return error; } + (NSError *)executeUpdateQuery:(NSString *)query args:(va_list)args { NSLogv(query,args); return nil; } 

这可以从Swift中调用

 MyClassName.executeUpdateQuery("query %d, %d %d", args: getVaList([1,2,3,4])) 

添加一个扩展来支持本地的Swift variadic参数:

 protocol CFormatFunction { class func executeUpdateQuery(format: String, _ args: CVarArg...) -> NSError? } extension MyClassName : CFormatFunction { class func executeUpdateQuery(format: String, _ args: CVarArg...) -> NSError? { return MyClassName.executeUpdateQuery(format, args:getVaList(args)) } } MyClassName.executeUpdateQuery("query %d %@ %.2f", 99, "Hello", 3.145) 

小心,Swift不提供NS_FORMAT_FUNCTION警告(-Wformat)

 MyClassName.executeUpdateQuery("query %@", 99) 

CVArgType在Swift CVArgType呈现C“可变参数”API时非常有用。 (Swift Docs)

如果你有

 + (int)f1:(int)n, ...; 

你首先需要制作一个va_list版本:

 + (int)f2:(int)n withArguments:(va_list)arguments 

这可以通过调用variadic版本的va_list版本而不需要复制代码来完成。 如果你没有写出原始的可变参数函数,那么可能不可能(在这个参考文献中解释过)。

一旦你有这个方法,你可以写这个Swift包装器:

 func swiftF1(x: Int, _ arguments: CVarArgType...) -> Int { return withVaList(arguments) { YourClassName.f2(x, withArguments :$0) } } 

请注意省略的外部参数名称( _之前的arguments ),这使得swiftF1的调用语法就像正常的C可变参数函数一样:

 swiftF1(2, some, "other", arguments) 

还要注意 ,这个例子不使用getVaList因为文档说这是“最好的避免”。

如果你愿意,你可以进一步把这个函数放在原始类的Swift扩展中。

在目标C中

MyClassName.h

 + (BOOL)executeSQL:(NSString *)sql args:(va_list)args; 

MyClassName.m

 + (BOOL)executeSQL:(NSString *)sql args:(va_list)arguments { NSLogv(sql, arguments); sql = [[NSString alloc] initWithFormat:sql arguments:arguments]; va_end(arguments); } 

Swift – 在其类中添加Works完美

 protocol CFormatFunction { class func executeSQLArg(format: String, _ args: CVarArgType...) -> Bool } extension MyClassName : CFormatFunction { class func executeSQLArg(format: String, _ args: CVarArgType...) -> Bool { return MyClassName(format, args:getVaList(args)) } } 

如何使用

迅速

 MyClassName.executeSQLArg(query, "one","two",3) 

目标C

 [MyClassName executeSQLArg:query, @"one",@"two",@3]