如何从Swift调用Objective-C变量法?

时间:2023-01-15 14:20:57

Supposing I have a class in Objective-c with a static method like this:

假设我有一个Objective-c类有一个静态方法

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

How do I call that from Swift? The autocomplete doesn't recognise it, and the compiler is unhappy with:

我怎么从斯威夫特那里打电话过来?自动补全不能识别它,编译器不满意:

MyClassName.executeUpdateQuery("")

Complaining that 'MyClassName.Type does not have a member named executeUpdateQuery'

抱怨的MyClassName。类型没有名为executeUpdateQuery的成员'

3 个解决方案

#1


40  

Write a va_list version of your variadic method;

编写变量方法的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;
}

This can then be called from Swift

这可以从Swift调用

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

Add an extension to support native Swift variadic args:

添加一个扩展来支持本地Swift可变参数args:

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)

Be careful, Swift doesn't provide NS_FORMAT_FUNCTION warnings (-Wformat)

注意,Swift没有提供NS_FORMAT_FUNCTION警告(-Wformat)

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

#2


4  

CVArgType is useful in presenting C "varargs" APIs natively in Swift. (Swift Docs)

CVArgType在Swift本地表示C“varargs”api时非常有用。(迅速文档)

If you have

如果你有

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

you first need to make a va_list version:

您首先需要创建一个va_list版本:

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

This can be done without duplicating code by calling the va_list version from the variadic version. If you didn't write the original variadic function it may not be possible (explained in this reference).

通过从variadic版本调用va_list版本,无需重复代码即可实现。如果您没有编写原始的变量函数,那么它可能是不可能的。

Once you have this method, you can write this Swift wrapper:

一旦您有了这个方法,您就可以编写这个Swift包装器:

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

Note the omitted external parameter name (_ before arguments), which makes the call syntax for swiftF1 just like a normal C variadic function:

注意省略的外部参数名(在参数之前),这使得swiftF1的调用语法与普通的C变量函数类似:

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

Note also that this example doesn't use getVaList because the docs say it is "best avoided."

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

You can further put this function in a Swift extension of the original class, if you want.

如果您愿意,您可以进一步将该函数添加到原始类的快速扩展中。

#3


1  

In Objective C

在Objective - C

MyClassName.h

MyClassName.h

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

MyClassName.m

MyClassName.m

+ (BOOL)executeSQL:(NSString *)sql args:(va_list)arguments
{
    NSLogv(sql, arguments);

    sql = [[NSString alloc] initWithFormat:sql arguments:arguments];
    va_end(arguments);
}

Swift - add in its class Works perfect

Swift -添加到它的类工作完美

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

How to use

如何使用

Swift

斯威夫特

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

Objetive C

Objetive C

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

#1


40  

Write a va_list version of your variadic method;

编写变量方法的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;
}

This can then be called from Swift

这可以从Swift调用

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

Add an extension to support native Swift variadic args:

添加一个扩展来支持本地Swift可变参数args:

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)

Be careful, Swift doesn't provide NS_FORMAT_FUNCTION warnings (-Wformat)

注意,Swift没有提供NS_FORMAT_FUNCTION警告(-Wformat)

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

#2


4  

CVArgType is useful in presenting C "varargs" APIs natively in Swift. (Swift Docs)

CVArgType在Swift本地表示C“varargs”api时非常有用。(迅速文档)

If you have

如果你有

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

you first need to make a va_list version:

您首先需要创建一个va_list版本:

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

This can be done without duplicating code by calling the va_list version from the variadic version. If you didn't write the original variadic function it may not be possible (explained in this reference).

通过从variadic版本调用va_list版本,无需重复代码即可实现。如果您没有编写原始的变量函数,那么它可能是不可能的。

Once you have this method, you can write this Swift wrapper:

一旦您有了这个方法,您就可以编写这个Swift包装器:

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

Note the omitted external parameter name (_ before arguments), which makes the call syntax for swiftF1 just like a normal C variadic function:

注意省略的外部参数名(在参数之前),这使得swiftF1的调用语法与普通的C变量函数类似:

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

Note also that this example doesn't use getVaList because the docs say it is "best avoided."

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

You can further put this function in a Swift extension of the original class, if you want.

如果您愿意,您可以进一步将该函数添加到原始类的快速扩展中。

#3


1  

In Objective C

在Objective - C

MyClassName.h

MyClassName.h

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

MyClassName.m

MyClassName.m

+ (BOOL)executeSQL:(NSString *)sql args:(va_list)arguments
{
    NSLogv(sql, arguments);

    sql = [[NSString alloc] initWithFormat:sql arguments:arguments];
    va_end(arguments);
}

Swift - add in its class Works perfect

Swift -添加到它的类工作完美

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

How to use

如何使用

Swift

斯威夫特

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

Objetive C

Objetive C

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