一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情。
为了便于理解**MemoryLayout**,我们先来看下下面这个例子:
struct ZGTeacher {
var age: Int = 18
}
let size = MemoryLayout<ZGTeacher>.size
let stride = MemoryLayout<ZGTeacher>.stride
let alignment = MemoryLayout<ZGTeacher>.alignment
print(size, stride, alignment)
lldb打印结果
8 8 8
我们给ZGTeacher结构体新增一个Bool属性看一下它的变化。
struct ZGTeacher {
var age: Int = 18
///新增一个Bool属性
var sex: Bool = true
}
省略......
lldb打印结果如下:
9 16 8
其中 alignment 是不变的,但是 size 和 stride 都变了。
MemoryLayout是Swift标准库中定义的一个枚举,顾名思义其是用于获取内存相关信息,MemoryLayout<Int> 则是一种泛型的用法,调用其**size属性可以获取某种数据类型所占内存空间的字节数,是其在内存中真实占用大小。调用其stride属性可以获取某种数据类型所开辟内存空间的字节数,是系统为其分配的内存大小。调用其alignment**属性可以获取某种数据类型所需要的对齐信息,指的是其当前内存对齐方式,是1字节对齐,4字节对齐等。
这⾥我们回到我们的指针操作,此时我们应该明⽩我们在存储 4 个连续整型的数据时候的问题了,那么 就是我们并没有指定当前 Int 数据在排列过程中每个数据和每个数据之间的间隔是多少?
代码修改如下:
///advanced 移动对应的步长,来存放内容
let size = MemoryLayout<Int>.size
let stride = MemoryLayout<Int>.stride
let alignment = MemoryLayout<Int>.alignment
let p = UnsafeMutableRawPointer.allocate(byteCount: 4 * stride, alignment: alignment)
for i in 0 ..< 4 {
p.advanced(by: i * stride).storeBytes(of: i, as: Int.self)
///(p + i * stride).storeBytes(of: i, as: Int.self)
}
print(p)
for i in 0 ..< 4 {
let value = p.load(fromByteOffset: i * 8, as: Int.self)
print("index: (i), value: (value)")
}
p.deallocate()
lldb打印结果:
0x0000000105058e30
index: 0, value: 0
index: 1, value: 1
index: 2, value: 2
index: 3, value: 3
这才是正确的,符合我们期望的存储内容打印。
其中
p.advanced(by: i * stride).storeBytes(of: i, as: Int.self)
也等价于
///p,基地址,i *stride,移动对应的步长位置来存放i
(p + i * stride).storeBytes(of: i, as: Int.self)
1.2.2 泛型指针的使用
这⾥的泛型指针相⽐较原⽣指针来说,其实就是指定当前指针已经绑定到了具体的类型。同样的,我们 还是通过⼀个例⼦来解释⼀下。
var age = 18
withUnsafePointer(to: &age) { ptr in
print(ptr)
}
lldb输出打印
0x0000000100008058
我们得到了age这个变量的内存指针。那么如果我们想要修改age这个变量可以怎么办哪?
在进⾏泛型指针访问的过程中,我们并不是使⽤ load 和 store ⽅法来进⾏存储操作。这⾥我们使⽤到当前泛型指针内置的变量 pointee。 获取 UnsafePointer 的⽅式有两种。
⼀种⽅式就是通过已有变量获取,如下:
var age = 18
withUnsafePointer(to: &age) { ptr in
print(ptr)
}
age = withUnsafePointer(to: age) { ptr in
return ptr.pointee + 20
}
print(age)
发现更改后,它的存储地址和存储的值已经发生改变。
0x0000000100008068
38
注意一点,这里我们无法直接修改**ptr.pointee,如果想要修改,我们可以通过可变类型的MutablePointer**,代码如下:
var age = 18
withUnsafePointer(to: &age) { ptr in
print(ptr)
}
withUnsafeMutablePointer(to: &age) { ptr in
ptr.pointee += 50
}
print(age)
lldb输出打印结果:
x0000000100008068
68
还有一种方式就是直接分配内存
var age = 18
///1、分配一块Int类型的内存空间,注意这个时候当前内存空间还没有被初始化
let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1)
///2、为age initialize初始化分配的内存空间
ptr.initialize(to: age)
///3、访问当前内存的值,直接通过pointee属性来进行访问
print(ptr.pointee)