Swift编程语言是一门灵活、简洁、安全而又强大的编程语言。其简洁性与安全性从它语法设计上就能看出。而它的高效性从它可以提供针对硬件底层进行编程的特性就能看出。尤其是从Swift 2.x中,其指针类型的使用变得更加灵活,甚至可以直接将一个整数作为地址,使得单纯通过Swift本身即可访问MMR寄存器。不过本博文将描述它另一个非常棒的特性——即与C API几乎完美的兼容!

Swift编程语言与C语言的交互同Java、C#还不太一样,由于Swift的运行时非常小,它基本用于作为静态编译的编程语言进行使用,因此最终可以直接生成二进制目标文件与其他编程语言得到的二进制目标文件进行连接。所以它天生就能非常自然地与C语言、Objective-C进行交互使用。关于Swift与C语言指针类型的对应表可参考Apple官方的《Using Swift with Cocoa and Objective-C》文档。

Swift 3.0中引入了UnsafeRawPointer对应于C语言的const void *类型;UnsafeMutableRawPointer对应于void*类型,然后为它提供了显式转换为指向其他类型的指针对象的方法——assumingMemoryBound(to:)对于指向不同对象类型的指针类型转换提供了withMemoryRebound(to:capacity:_:)方法。这些都可以参考此博文:http://www.jb51.cc/article/p-hjqzrjzn-bpc.html。本博文主要将介绍对于更复杂的多级指针类型,在Swift编程语言中如何体现;倘若我们要将一个Swift函数暴露给C语言使用,涉及到指针类型的话该如何判断。

我们先举一些例子,这里提供了TestPtr1道TestPtr5这5个函数,参数为一个指针对象,这些函数的形参类型由简单到复杂依次推进,所以我们可以更清晰地做类型分析。

首先是Swift与C桥接的头文件内容:

extern void TestPtr1(int * _Nonnull);
extern void TestPtr2(const int* _Nonnull);
extern void TestPtr3(int * _Nonnull * _Nonnull);
extern void TestPtr4(const int * _Nonnull * _Nonnull);
extern void TestPtr5(int const * _Nonnull const * _Nonnull);
上述函数原型声明中,为了简化指针类型的讨论,我们都将它们声明为_Nonnull属性。然后我们看看下面的C源文件对这些函数的实现:
#include <stdio.h>

static int s = 100;

void TestPtr1(int *p)
{
    *p += 10;
    printf("This is: %s\n",__func__);
}

void TestPtr2(const int *p)
{
    printf("This is: %s,*p = %d\n",__func__,*p);
}

void TestPtr3(int **pp)
{
    *pp = &s;
    printf("This is: %s\n",__func__);
}

void TestPtr4(const int **pp)
{
    *pp = &s;
    printf("This is: %s\n",__func__);
}

void TestPtr5(int const * const *pp)
{
    printf("This is: %s,**pp = %d\n",**pp);
}
上述函数的实现都非常简单。因为我们主要关心的指针类型到Swift中所对应的类型。此外,我们可以看到函数形参从p到pp,类型由简单到复杂。

好!下面我们就来看看Swift源文件内容:

        var a: Int32 = 1
        
        // TestPtr1的类型为:(UnsafeMutablePointer<Int32>) -> Void
        TestPtr1(&a)
        
        // TestPtr2的类型为:(UnsafePointer<Int32>) -> Void
        TestPtr2(&a)
        
        // 这里制作一个指向变量a的指针变量
        var aptr = withUnsafeMutablePointer(to: &a) {
            return $0
        }
        
        // TestPtr3的类型为:(UnsafeMutablePointer<UnsafeMutablePointer<Int32>>) -> Void
        TestPtr3(&aptr)
        
        // 我们这里可以看到,aptr已经被间接修改了,此时它指向了C源文件中定义的静态变量s的地址
        print("aptr's content: \(aptr.pointee)")
        
        // 我们这里通过aptr对它所指向的静态变量s做间接修改
        aptr.pointee += 100
        
        // 我们这里制作一个指向变量a的指针常量
        var cptr = withUnsafePointer(to: &a) {
            return $0
        }
        
        // TestPtr4的类型为:(UnsafeMutablePointer<UnsafePointer<Int32>>) -> Void
        TestPtr4(&cptr)

        // 我们这里可以看到,cptr也被间接修改,指向了C源文件中的静态变量s的地址。
        // 同时,我们也可以看到,静态变量s的值变成了200
        print("cptr's content: \(cptr[0])")
        
        // TestPtr5的类型为:(UnsafePointer<UnsafePointer<Int32>>) -> Void
        TestPtr5(&cptr)
通过强大的Xcode开发环境,它所提供的代码智能感知,我们只要输入某个函数名,那么其参数类型就会被自动展现出来,十分方便!

那么如果我们要实现一个Swift函数,其对应的C语言的指针类型该如何判定呢?其实规则非常简单!下面我将为大家介绍对应方法。

1、首先,在Swift中,一个变量是用var声明的,它对应到C语言中就是类型名,这里用Type表示。而一个常量是用let声明的,对应到C语言中用const Type表示。

2、Swift中引入了UnsafeMutablePointer<T>用于表示一个指针对象,它对应C语言中的 T* 。

3、Swift中引入了UnsafePointer<T>用于表示一个指针对象,并且对该指针所访问的值做了常量限定,因此它对应C语言的 const T * 。

好了,下面我们将根据上述三种类型的对应关系扩展到多级指针的类型对应法则上。首先,对于UnsafeMutablePointer< UnsafeMutablePointer<T> >类型,它对应于C语言的哪种类型就十分容易判定了,首先是最外层的UnsafeMutablePointer表示为 * ,因此,我们将先把 * 写好。然后看它里面的类型,也是UnsafeMutable,那么我们在第一个 * 之前再添加一个 * 。最后,在UnsafeMutablePointer泛型实参中看到的是T,那么我们将T放在最前面,因此得到C语言对应的类型为 T** 。

而对于UnsafeMutablePointer< UnsafePointer<T> >类型也如法炮制:先写好 * ,然后里边是一个UnsafePointer,表示指向一个常量对象类型的指针,因此我们用 const * 来表示,所以在第一个 * 之前添加之后可得到 const * *。而UnsafePointer中的泛型实参为T,因此最后得到C语言类型为 T const * *,通常也表示为const T * *。

而对于UnsafePointer< UnsafeMutablePointer<T> >类型呢?首先,UnsafePointer对应的是指向常量对象的指针,因此我们用 const *来表示。它里面的UnsafeMutablePointer则同样用 * 表示,放到 const *之前,得到 * const *。最后,UnsafeMutablePointer里面的T放到最前面可得:T * const * 。

最后,UnsafePointer< UnsafePointer<T> >则很容易就能判断出来了——最外层的UnsafePointer先写好:const *。然后里面的附加上:const * const *。最后把 T加上,得:T const * const *。整理后,得到:const T * const *。

Swift 3.0与C语言指针类型的桥接的更多相关文章

  1. html5利用canvas实现颜色容差抠图功能

    这篇文章主要介绍了html5利用canvas实现颜色容差抠图功能,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  2. Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式)

    这篇文章主要介绍了Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. ios – 如何使用Objective C类中的多个参数调用Swift函数?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  4. ios – Swift 4添加手势:覆盖vs @objc

    我想在我的视图中添加一个手势,如下所示:但是,在Swift4中,我的编译器给出了以下错误:建议添加@objc以将此实例方法公开给Objective-C.实现此目的的另一个选项将覆盖touchesBegan()函数并使用它来处理点击.我试图以“Swift”的方式做到这一点,而不必带入Obj-C.有没有纯粹的Swift方式来添加这个轻击手势而不使用@objc?

  5. ios – 将视频分享到Facebook

    我正在编写一个简单的测试应用程序,用于将视频从iOS上传到Facebook.由于FacebookSDK的所有文档都在Objective-C中,因此我发现很难在线找到有关如何使用Swift执行此操作的示例/教程.到目前为止我有这个在我的UI上放置一个共享按钮,但它看起来已禁用,从我读到的这是因为没有内容设置,但我看不出这是怎么可能的.我的getVideoURL()函数返回一个NSURL,它肯定包含视

  6. ios – 以编程方式在Swift中添加联系人

    我想在Swift中以编程方式添加联系人.我发现了一些Objective-C示例,但我没有让它们工作,甚至在Objective-C中也没有.我不希望这涉及到AddressBookUI,因为我想从我自己的UI中获取值.解决方法这是在Swift中添加联系人的快速方法.我在我的iPhone5iOS7.1上验证了它,因为我发现模拟器并不总是与我的手机对AB的东西相同.您可以添加一个按钮并指向此方法:顺便说一下–它假设你已经分配了一个地址簿var,你可以通过覆盖viewDidAppear来打开视图.它也会执行安全提示

  7. ios – 为目标c中的方法传递未知类型的参数,可能吗?

    是否可以将未知类型的参数传递给objective-C方法?在C#中你可以写实现这一点,但我知道Objective-C没有泛型,所以有没有其他方法可以在Objective-C中实现这一点?我需要这个,因为我想创建一个方法来改变不同对象的文本颜色,如UITextField和UIButton的占位符文本.所以我的计划是创建一个名为textWhite的方法,然后在此方法中检查对象的类型,然后运行匹配的代码以使文本颜色变为白色.解决方法是的,可以传递未知类型的参数.见下面的例子.请参考使用id对象的链接作为参数Us

  8. ios – Swift指针算术和解除引用;将一些类似C的地图代码转换为Swift

    我有一点似乎没有工作的Swift代码……解决方法您正在指定locationPointer指向新位置,但仍在下一行中使用ptr,并且ptr的值尚未更改.将您的最后一行更改为:或者你可以改变指向var的指针并推进它:

  9. ios – “禁用模块时使用’@import’”错误 – 启用模块和链接框架= YES

    我有一个使用CocoaPods并使用’SCLAlertView-Objective-C’窗格的项目.该pod使用@importUIKit;模块样式导入.我在目标和项目设置中将“启用模块(C&Objective-C)”和“自动链接框架”设置为YES.当模块被禁用时,我仍然得到“使用’@import’错误.有没有什么可以阻止Xcode能够启用模块,如使用.pch文件,任何链接器标志,或者我没有提到的任

  10. XCode 6.3立即在抛出的Objective-C异常上引发SIGABRT

    考虑以下目标-C代码在XCode6.2中,它按预期工作(记录“错误消息”).但是,由于我们升级到6.3,抛出行(throwstd::logic_error…)引发SIGABRT(堆栈跟踪仅包含_cxa_throw和_pthread_kill,超出applicationdidFinishLaunchingWithOptions)并导致应用程序崩溃.这只发生在我们的应用程序中–当我将完全相同的代码复制

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部