Swift中的指针操作和使用详细介绍

2020-01-08 22:46:29于丽

上面我们说过,在Swift中不能像C里那样使用&符号直接获取地址来进行操作。如果我们想对某个变量进行指针操作,我们可以借助withUnsafePointer这个辅助方法。这个方法接受两个参数,第一个是 inout的任意类型,第二个是一个闭包。Swift会将第一个输入转换为指针,然后将这个转换后的Unsafe的指针作为参数,去调用闭包。使用起来大概是这个样子:

复制代码
var test = 10  
test = withUnsafeMutablePointer(&test, { (ptr: UnsafeMutablePointer<Int>) -> Int in  
    ptr.memory += 1  
    return ptr.memory  
})  
test // 11  
这里其实我们做了和文章一开始的incrementor相同的事情,区别在于不需要通过方法的调用来将值转换为指针。这么做的好处对于那些只会执行一次的指针操作来说是显而易见的,可以将“我们就是想对这个指针做点事儿”这个意图表达得更加清晰明确。

 

unsafeBitCast

unsafeBitCast是非常危险的操作,它会将一个指针指向的内存强制按位转换为目标的类型。因为这种转换是在Swift的类型管理之外进行的,因此编译器无法确保得到的类型是否确实正确,你必须明确地知道你在做什么。比如:

复制代码
let arr = NSArray(object: "meow")  
let str = unsafeBitCast(CFArrayGetValueAtIndex(arr, 0), CFString.self)  
str // “meow”  
因为NSArray是可以存放任意NSObject对象的,当我们在使用CFArrayGetValueAtIndex从中取值的时候,得到的结果将是一个UnsafePointer<Void>。由于我们很明白其中存放的是String对象,因此可以直接将其强制转换为CFString。

 

关于unsafeBitCast一种更常见的使用场景是不同类型的指针之间进行转换。因为指针本身所占用的的大小是一定的,所以指针的类型进行转换是不会出什么致命问题的。这在与一些C API协作时会很常见。比如有很多C API要求的输入是void *,对应到Swift中为UnsafePointer<Void>。我们可以通过下面这样的方式将任意指针转换为UnsafePointer。

复制代码
var count = 100  
var voidPtr = withUnsafePointer(&count, { (a: UnsafePointer<Int>) -> UnsafePointer<Void> in  
    return unsafeBitCast(a, UnsafePointer<Void>.self)  
})