前言:
上篇文章总结分析了swift的数据类型值类型
和引用类型
,在分析的过程中提到了withUnsafePointer
方法,这篇文章着重分析这个pointer
指针
指针的含义
指针
就是内存地址
,指针变量
是用来存放内存地址
的变量
,不同类型的指针变量
所占用的存储单元长度
是相同
的,而存放数据的变量
因数据的类型不同,所占用的存储空间
长度也不同。有了指针以后,不仅可以对数据本身
,也可以对存储数据的变量地址
进行操作。
Swift中指针的分类
Swift中的指针分为两类:
-
typed pointer
指定数据类型指针,即UnsafePointer<T>
,其中T表示泛型 -
raw pointer
未指定数据类型的指针(原生指针) ,即UnsafeRawPointer
Swift与OC指针对应关系:
原生指针的使⽤
概念:
原生指针:是指未指定数据类型
的指针,特点是对于指针
的内存管理
是需要手动
管理的,在使用完需要手动释放
假设我们想在内存中存储连续
4 个整形(100,101,102,103)的数据,我们如何使⽤raw pointer
来做
/**
* 原生指针
* RawPionter的使⽤
* 定义一个未知类型的指针:本质是分配32字节大小的空间,指定对齐方式是8字节对齐
*/
let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)
/**
* 存储
* advanced代表当前 p 前进的步⻓,对于 RawPointer 来说,我们需要移动的是 当前存储值得内存⼤⼩即,MemoryLayout.stride
* storeBytes: 这⾥就是存储我们当前的数据,这⾥需要制定我们当前数据的类型
*/
for i in 0..<4 {
p.advanced(by: i * 8).storeBytes(of: i + 100, as: Int.self)
}
/**
* 读取
* load顾明思义是加载,fromBytesOffe:是相对于我们当前 p 的⾸地址的偏移
*/
for i in 0..<4 {
let value = p.load(fromByteOffset: i * 8, as: Int.self)
print("index: \(i), value: \(value)")
}
/**
* 使用完成需要dealloc,即需要手动释放
*/
p.deallocate()
运行结果:
type pointer
typed point
是指定类型的指针,我们在使用typed point
的使用,会明确知道该指针指向的类型。它包含了一共四个子类型,他们分别是:
-
UnsafePointer
-
UnsafeMutablePointer
-
UnsafeBufferPointer
-
UnsafeMutableBufferPointer
**
- UnsafePointer
**UnsafePointer
的官方描述是 访问特定类型数据的指针
。意即这个指针的类型是已知。已知的内存有三种状态:
未绑定类
型同时未初始化值
绑定类型
但是未初始化值
绑定类型
同时初始化值
这里的**UnsafePointer
就是指向绑定类型同时初始化值
**内存的,它相当于C系列语言中的const
对象,我们不能直接初始化UnsafePointer
对象,也不能修改UnsafePointer
指向的值,因为这是一个常量指针
!
使用
使用继承UnsafePointer
查看
使用swift提供的with函数
获取基本数据类型的地址是通过withUnsafePointer(to:)
方法获取的,查看withUnsafePointer(to:)
方法参数:
- UnsafeMutablePointer
它相当于C系列语言中的变量指针
。
在C语言中:
int *p = malloc(sizeof(int));
在Swift中定义一个指针变量
let usmp = UnsafeMutablePointer<Int>.allocate(capacity: sizeof_sfntInstance)
两者的意义相同。
我们同样可以通过 pointee
属性发访问指针的值。同时,你还可以直接修改 pointee
的值,就像我们使用Swift的其他类一样
使用:
- UnsafeBufferPointer
UnsafeBufferPointer
指代一系列连续的内存。我们可以使用这个指针作为一个序列的指针,并通过指针直接访问旗下元素.
使用:
- UnsafeMutableBufferPointer
可变指针。UnsafeMutableBufferPointer
拥有对指向序列修改的能力
使用:
raw pointer
raw pointer
指未知类型的指针,这个类型相当于C语言中的(void *
)类型,。
同样的,raw pointer
也包含了四个子类型:
- UnsafeRawPointer
- UnsafeMutableRawPointer
- UnsafeBufferRawPointer
- UnsafeMutableBufferRawPointer
- UnsafeRawPointer & UnsafeMutableRawPointer
UnsafeRawPointer
UnsafeRawPointer
类型不提供自动内存管理,也不保证其内存,同时没有做任何的内存对齐,在使用UnsafeRawPointer
的时候,应该手动对指针做内存管理,以避免泄漏或未定义的行为.
UnsafeRawPointer
不能直接创建,要借助UnsafeMutableRawPointer
实现
UnsafeMutableRawPointer
raw pointer
没有指定内存的类型,也没有初始化的值,他只是开辟了一块内存,也不知道它指向的那个内存中存的什么。所以它不包含pointee
这个属性了。虽然我们不知道raw pointer
指向的内存中存什么,但是我们可以通过raw pointer
的 advanced(by:)
函数获取之后的地址的块区。每一次调用advanced(by:)
都会返回一个地址。如果将之后的地址绑定
某个类型之后,我们就可以在这个地址的片区中赋值了。
使用advanced
函数根据p的地址
偏移16位
得到新的内存地址
绑定类型
由上图可知:绑定过
的raw pointer
就变成了typed pointer
- UnsafeBufferRawPointer & UnsafeMutableBufferRawPointer
UnsafeRawBufferPointer
和UnsafeMutableRawBufferPointer
指代的是一系列的没有被绑定类型的内存区域.UnsafeRawBufferPointer
和UnsafeMutableRawBufferPointer
知道它指向的内存区域,但是它并不拥有这块内存的引用。复制UnsafeRawBufferPointer
类型的变量不会复制它的内存,但是初始化一个集合到另一个新的集合过程会复制集合中的引用内存。
查看UnsafeRawBufferPointer
使用UnsafeMutableRawBufferPointer
:
指针实例应用
访问结构体实例对象
其他访问方式
实例对象绑定到struct内存
根据Swift源码
中的HeapObject
,自定义我们自己的lg_swift_Class
struct HeapObject {
var kind: UnsafeRawPointer
var strongref: UInt32
var unownedRef: UInt32
}
struct lg_swift_class {
var kind: UnsafeRawPointer
var superClass: UnsafeRawPointer
var cachedata1: UnsafeRawPointer
var cachedata2: UnsafeRawPointer
var data: UnsafeRawPointer
var flags: UInt32
var instanceAddressOffset: UInt32
var instanceSize: UInt32
var flinstanceAlignMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressOffset: UInt32
var description: UnsafeRawPointer
}
class LGTeacher{
var age = 18
}
结构体绑定:
绑定到类结构:
元组指针类型转换
获取结构体的属性的指针
withPoint系列方法
public func withUnsafeMutablePointer<T, Result>(to arg: inout T, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result
public func withUnsafePointer<T, Result>(to arg: inout T, _ body: (UnsafePointer<T>) throws -> Result) rethrows -> Result
public func withExtendedLifetime<T, Result>(_ x: T, _ body: (T) throws -> Result) rethrows -> Result
public func withExtendedLifetime<T, Result>(_ x: T, _ body: () throws -> Result) rethrows -> Result
使用前面两个函数的概率更高,如果使用withUnsafeMutablePointer(to:)
方法修改属性值
,必须保证属性的类型是var
,虽然在内部我们可以使用初始化指针的方式强行改变,但是在调用方法时,编译器会提示需要加入一个 var 的变量
,而不能
是常量
.
总结
-
指针类型分两种:
typed pointer
指定数据类型指针,即UnsafePointer<T>
,其中T表示泛型raw pointer
未指定数据类型的指针(原生指针) ,即UnsafeRawPointer
,他们的几个子类都是以unsafe
开头,这同时也在告知使用者,在Swift 中使用指针
是不安全
的。 -
在使用原生指针(
UnsafeRawPointer
)时,请指定内存的大小
,使用完毕时,请及时释放
.