前景
Swift 中指针被映射为了一个泛型类型,苹果希望我们在Swift开发中尽量减少指针的使用。指针类型都是泛型的 struct,开发者可以通过这个泛型来对指针指向的类型进行约束以提供一定安全性。
简介
- UnsafePointer: 不可变指针类型
- UnsafeMutablePointer: 可变指针类型
- UnsafeBufferPointer: 一组连续数据指针
- COpaquePointer: 非完整结构的不透明指针
。。。。
使用
不可变指针,可以通过 pointee 属性进行取值。 可变指针可以通过 pointee 进行赋值。
在变量名前面加上 & 符号就可以将指向这个变量的指针传递到接受指针作为参数的方法中去。虽然 & 在参数传递时表示的意义和 C 中一样,是某个“变量的地址”,但是在 Swift 中我们没有办法直接通过这个符号获取一个 UnsafePointer 的实例。需要注意这一点和 C 有所不同。
例子
func addNum(ptr: UnsafeMutablePointer<Int>) {
ptr.pointee += 1
}
var a = 100
addNum(&a)
a // 101
与之对应的Swift 中提供了 inout 关键字 ,不过区别是在函数体内部我们不需要处理指针类型,而是可以对参数直接进行操作。
例子
func addNum(inout num: Int) {
Num += 1
}
var a = 100
addNum(&a)
a // 101
指针初始化和内存管理
指针的内存管理,需要程序员手动的去申请和释放,UnsafeMutablePointer: 用于创建新的指针对对象
UnsafeMutablePointer 的内存有三种可能状态:
- 内存没有被分配,这意味着这是一个 null 指针,或者是之前已经释放过
- 内存进行了分配,但是值还没有被初始化
- 内存进行了分配,并且值已经被初始化
只有第三种状态下的指针是可以保证正常使用,例子
initialize(to:) : 进行内容初始化
deinitialize:: 用来销毁指针指向的对象。
allocate(capacity:) : 系统申请 capacity 个数的对应泛型类型的内存
deallocate(capacity:) : 释放之前申请的内存
//使用 allocate(capacity:) 这个类方法去创建一个指针。该方法根据参数 capacity: Int 向系统申请 capacity 个数的对应泛型类型的内存。下面的代码申请了一个 Int 大小的内存,并返回指向这块内存的指针:
var intPtr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
intPtr.initialize(to: 100)
// intPtr.pointee 为 100
在使用之后,我们最好尽快释放指针指向的内容和指针本身。与 initialize: 配对使用的 deinitialize: 用来销毁指针指向的对象,而与 对应的 用来。它们都应该被配对使用.
withUnsafePointer / withUnsafeMutablePointer: 指针的操作
Swift 中不能像 C 里那样使用 & 符号直接获取地址来进行操作。如果我们想对某个变量进行指针操作,我们可以借助 withUnsafePointer 或 withUnsafeMutablePointer 这两个辅助方法
var a = 100
a = withUnsafeMutablePointer(to: &a, { (ptr: UnsafeMutablePointer<Int>) -> Int in
ptr.pointee += 1
return ptr.pointee
})
a // 101
unsafeBitCast: 指针类型转换,它会将一个指针指向的内存强制按位转换为目标的类型,因此编译器无法确保得到的类型是否确实正确,你必须明确地知道你所转变的类型正确。
let arr = NSArray(object: "abc")
let str = unsafeBitCast(CFArrayGetValueAtIndex(arr, 0), to: CFString.self)
str // “abc”
总结
在Swift 开发中,能不用指针尽量不使用。