Swift 3.0在2.0基础上做了许多改动,其中之一就是与C API的兼容性上。这里我将主要讲解一下C语言的指针与Swift编程语言的桥接在Swift 3.0中改成啥样了。
首先,为了Swift编程语言语法体系的统一性,Swift语言核心设计团队为所有诸如UnsafePointer、UnsafeMutablePointer等类型增加了Optional,这个在Swift 2.x中是没有的,不过你可以直接对一个UnsafePointer<Int32>类型的对象置空。而在3.0版本中增加了这些类型的Optional属性之后,我们就可以把它们作为其他类型一样去对待了。
然后,Swift 3.0给void*和const void*分别引入了UnsafeRawPointer类型和UnsafeMutableRawPointer类型。而在Swift 2.x中,它们分别对应的是UnsafePointer<Void>与UnsafeMutablePointer<Void>。此外,UnsafeRawPointer类型与UnsafeMutableRawPointer类型不能直接通过UnsafePointer与UnsafeMutablePointer的构造器转换为相应类型,而只能通过它们的assumingMemoryBound(to:)方法去转。
最后,UnsafePointer类型要转为UnsafeMutablePointer类型时现在必须使用UnsafeMutablePointer的init(mutating:)方法,这里增加了一个参数标签mutating。
下面我们将通过一段代码来呈现以上说的这三点。以下有3个代码片段,分别是一个头文件、一个C源文件和一个Swift源文件。
extern void* _Nonnull GenerateData(void); extern void UseData(const int* _Nonnull pData); extern const void* _Nullable GenerateData2(void); extern void UseData2(int* _Nullable pData);
#include <stdio.h> static int sData = 10; void* GenerateData(void) { return &sData; } void UseData(const int *pData) { printf("The data is: %d\n",*pData); } const void* _Nullable GenerateData2(void) { return &sData; } void UseData2(int *pData) { if(pData != NULL) printf("The data is: %d\n",pData[0]); }
class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() let dataPtr = GenerateData() // 这里可以看到,dataPtr的类型是UnsafeMutableRawPointer print("dataPtr type is: \(type(of: dataPtr))") // 这里先将dataPtr类型转换为UnsafeMutablePointer<Int32>类型 let dataInt32Ptr = dataPtr.assumingMemoryBound(to: type(of: Int32())) print("dataInt32Ptr type is: \(type(of: dataInt32Ptr))") // 我们还可以对指针所指向的整型数据做些修改 dataInt32Ptr.pointee += 10 // 在传递UseData的实参时,需要将dataInt32Ptr的类型再转为UnsafePointer<Int32> UseData(UnsafePointer<Int32>(dataInt32Ptr)) // 这里dataPtr2是UnsafeRawPointer?类型 let dataPtr2 = GenerateData2() // 这里dataInt32Ptr2的类型是UnsafePointer<Int32>? let dataInt32Ptr2 = dataPtr2?.assumingMemoryBound(to: type(of: Int32())) // 这里需要将dataInt32Ptr2类型转换为UnsafeMutablePointer<Int32> UseData2(UnsafeMutablePointer<Int32>(mutating: dataInt32Ptr2)) var intObj: Int32 = 0 // 这里可以看到,在Swift中的一个Int32类型对象, // 对它取地址操作也可以与UnsafePointer<Int32>类型进行匹配 UseData(&intObj) UseData2(&intObj) var uintObj: UInt = 1 // 如果要将一个UnsafePointer<UInt>转换为UnsafePointer<Int32>, // 现在无法直接用UnsafePointer的构造方法进行转换。 // 为了看清整个转换过程,我们先用withUnsafePointer来获取uintObj的指针类型对象 let uintPtr = withUnsafePointer(to: &uintObj) { (ptr: UnsafePointer<UInt>) -> UnsafePointer<UInt> in return ptr } // 这里使用了Swift 3新引入的UnsafePointer与UnsafeMutablePointer的 // withMemoryRebound(to:capacity:_:)方法显式地将当前指针的原始类型 // 转换为目标类型的指针对象。 // 这里的Int32.self相当于type(of: Int32()),获取到的是Int32元类型 UseData(uintPtr.withMemoryRebound(to: Int32.self,capacity: 1) { (ptr: UnsafePointer<Int32>) -> UnsafePointer<Int32> in return ptr }) // 为了看清下一步操作,我们这里将withMemoryRebound方法所返回的 // UnsafePointer<Int32>对象hold住 let constPtr = uintPtr.withMemoryRebound(to: Int32.self,capacity: 1) { (ptr: UnsafePointer<Int32>) -> UnsafePointer<Int32> in return ptr } } }
上述代码详细介绍了如何通过C语言函数接口获得一个指针类型,然后做相互转换。此外,还有在Swift中定义的对象如何作为指针类型的参数传入C语言函数中。这里涉及到了Swift 3.0中的新方法,包括UnsafeRawPointer与UnsafeMutableRawPointer的assumingMemoryBound(to:)方法;UnsafePointer与UnsafeMutablePointer的withMemoryRebound(to:capacity:_:)方法。Swift 3.0中取消了UnsafePointer与UnsafeMutablePointer构造方法对任意类型的指针进行转换的实现,取而代之的是,对于指针转换的数据类型都一致的情况,可以通过UnsafeMutablePointer中的init(mutating:)方法将UnsafePointer转换UnsafeMutablePointer;而UnsafePointer可直接使用init(_:)将UnsafeMutablePointer转换相应类型的UnsafePointer类型。除此之外,非相应数据类型的指针转换都必须使用withMemoryRebound(to:capacity:_:)方法。
各位可以在Xcode 8上尝试运行。
原文链接:https://www.f2er.com/swift/322547.html