你如何从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
在SwiftCVArgType
呈现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]