在这一节,我们来分享和函数有关的桥接工作。这是一个有些复杂的过程,根据函数参数和返回值的不同,桥接的方式也有差异。作为第一部分,我们先来看简单函数的桥接过程。所谓简单函数,就是指那些参数和返回值都是简单类型,并且不使用指针的函数。

固定参数个数的函数

固定参数个数的简单函数桥接到Swift时很简单,几乎会“原封不动”的桥接到Swift。例如,在traditional_oc.h中,声明一个全局函数:

int add(int m, int n);

并在traditional_oc.m中定义它:

int add(int m, int n) {
    return m + n;
}

在Swift里,add会变成这样:

func add(_ m: Int32, _ n: Int32) -> Int32 {
    return m + n
}

其中有两点需要注意:

  • C中桥街过来的函数默认都是省略external name的;
  • C中的int会自动转换成Int32,因此默认是不能传递Swift Int类型的,只能使用CInt类型;

不固定参数个数的函数

接下来,我们了解不固定参数个数的函数。在C里,我们有两种方法定义这样的函数,例如,先在traditional_oc.h中添加下面的声明:

int sum(int count, ...);
int vsum(int count, va_list numbers);

这两个函数的第一个参数表示后续不确定参数的个数,然后在traditional_oc.m中实现它们:

int sum(int count, ...) {
    va_list ap;
    int s = 0;

    va_start(ap, count);
    vsum(count, ap);
    va_end(ap);

    return s;
}

int vsum(int count, va_list numbers) {
    int s = 0;
    int i = 0;

    for (; i < count; ++i) {
        s += va_arg(numbers, int);
    }

    return s;
}

它们都是很简单的C代码,如果你还不熟悉C的可变参数函数,可以先在这里简单了解下,我们就不重复了。这两个函数会如何桥接到Swift呢?遗憾的是,Swift只能接受vsum,而不能接受sum。也就是说,无论如何都无法在Swift中直接调用sum函数。而vsum桥接到Swift之后,是这样的:

func vsum(count: Int32, numbers: CVaListPointer) -> Int32

因此,在Swift里,我们不能像vsum(6, 1, 2, 3, 4, 5, 6)这样调用vsum,那么这个CVaListPointer是什么呢?简单来说,它就是C中va_list桥接到Swift后对应的类型。为了得到这个对象,我们有两种方法。

第一种,是调用getVaList方法,并把要传递的可变参数作为一个数组传递给它:

let vaListPointer = getVaList([1, 2, 3, 4, 5, 6])
let sum = vsum(6, vaListPointer)

这样,我们就可以把vaListPointer作为vsum的第二个参数了。

第二种,是调用withVaList方法,它的第一个参数是一个数组,我们像调用getVaList一样把所有可变参数传递给它;第二个参数是一个closure,withVaList会根据第一参数中的所有成员,生成一个对应的CVaListPointer对象,并传递给这个closure。因此,我们只要在closure里调用vsum就好了:

let sum = withVaList([1, 2, 3, 4, 5, 6]) {
    vaListPointer in
    vsum(6, vaListPointer)
}

当然,这两种方法的结果,是完全一样的。

What's next?

以上,就是两种简单函数桥接到Swift时的处理方式,在进一步了解C函数和Swift的交互前,还要做不少铺垫工作,因此,我们先把这个话题放放。下一节,我们来看Swift如何处理C中的structunion

所有订阅均支持 12 期免息分期

¥ 59

按月订阅

一个月,观看并下载所有视频内容。初来泊学,这可能是个最好的开始。

开始订阅

¥ 512

按年订阅

一年的时间,让我们一起疯狂地狩猎知识吧。比按月订阅优惠 28%

开始订阅

¥ 1280

泊学终身会员

永久观看和下载所有泊学网站视频,并赠送 100 元商店优惠券。

我要加入
如需帮助,欢迎通过以下方式联系我们