¿Cómo llamas a un método variad Objective-C de Swift?

Supongamos que tengo una clase en Objective-c con un método estático como este:

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

¿Cómo llamo eso desde Swift? La función autocompletar no lo reconoce y el comstackdor no está satisfecho con:

 MyClassName.executeUpdateQuery("") 

Quejándose de que ‘MyClassName.Type no tiene un miembro llamado executeUpdateQuery’

Escriba una versión va_list de su método variadic;

 + (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; } 

Esto puede ser llamado desde Swift

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

Agregue una extensión para admitir args variadic nativas de Swift:

 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) 

Tenga cuidado, Swift no proporciona advertencias NS_FORMAT_FUNCTION (-Wformat)

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

CVArgType es útil para presentar API de C “varargs” de forma nativa en Swift. (Documentos Swift)

Si usted tiene

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

primero necesita hacer una versión de va_list :

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

Esto se puede hacer sin duplicar el código llamando a la versión va_list desde la versión variadic. Si no escribió la función original variadic, puede que no sea posible (se explica en esta referencia ).

Una vez que tenga este método, puede escribir este contenedor Swift:

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

Tenga en cuenta el nombre de parámetro externo omitido ( _ antes de los arguments ), que hace que la syntax de llamada para swiftF1 similar a una función variadic normal de C:

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

Tenga en cuenta también que este ejemplo no usa getVaList porque los documentos dicen que es “mejor evitarlo”.

Además, puede poner esta función en una extensión Swift de la clase original, si lo desea.

En el objective 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 – agregar en su clase Funciona perfecto

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

Cómo utilizar

Rápido

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

Objetivo C

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