一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
下面我们操作一个结构体来实践一下。
struct ZGTeacher {
var age: Int
var height: Double
}
下面我们来尝试看一下如何用指针来访问这个结构体。代码如下:
struct ZGTeacher {
var age: Int
var height: Double
}
///capacity: 比如我们需要开辟5个内存空间的大小
///allocate: 开辟空间
var ptr = UnsafeMutablePointer<ZGTeacher>.allocate(capacity: 5)
///初始化我们的指针内存,并存储对应的值
ptr[0] = ZGTeacher(age: 18, height: 20.0)
ptr[1] = ZGTeacher(age: 22, height: 30.0)
///defer关键字,当前程序运行完成后会执行这块代码
defer {
///deinitialize回收5个内存空间
ptr.deinitialize(count: 5)
///销毁对应的内存空间
ptr.deallocate()
}
我们同样还可以如下面代码这样初始化:
struct ZGTeacher {
var age: Int = 18
var height: Double = 1.85
}
let p = UnsafeMutablePointer<ZGTeacher>.allocate(capacity: 2)
p.initialize(to: ZGTeacher())
p.advanced(by: MemoryLayout<ZGTeacher>.stride).initialize(to: ZGTeacher(age: 20, height: 1.75))
defer {
p.deinitialize(count: 2)
p.deallocate()
}
1.3 内存绑定
swift提供了三种不同的API来绑定/重新绑定指针:
- assumingMemoryBound(to:)
func testPointer(_ p: UnsafePointer<Int>) {
print(p)
}
let tuple = (10, 20)
withUnsafePointer(to: tuple) { (tuplePtr: UnsafePointer<(Int, Int)>) in
testPointer(tuplePtr)
}
编译运行,发现报错了,如下图所示
那么想要顺利访问到元组的值我们可以怎么办哪? 首先,第一点,我们先把我们的指针转换为原生指针**UnsafeRawPointer,然后我们调用assumingMemoryBound**绑定成对应类型。
func testPointer(_ p: UnsafePointer<Int>) {
print(p[0], p[1])
}
let tuple = (10, 20)
withUnsafePointer(to: tuple) { (tuplePtr: UnsafePointer<(Int, Int)>) in
testPointer(UnsafeRawPointer(tuplePtr).assumingMemoryBound(to: Int.self))
}
编译一下,正确输出打印元组的值 10,20
那么我们使用assumingMemoryBound的意义是什么?
有时候我们的类型只有这种原生指针UnsafeRawPointer,或者说像UnsafePointer<(Int, Int)> 和UnsafePointer 这种,两种值类型相似,但是我们又不想经过一系列的转换操作来增加代码复杂度,对我们的指针进行生硬的转换,那么这个时候我们就可以使用这个API assumingMemoryBound来告诉我们的编译器自己预期的类型,不需要编译器再重复检查(注意:这⾥只是让编译器绕过类型检查,并没有发⽣实际类型的转换)。
- bindMemory(to: , capacity: )
调用**bindMemory**绑定成对应类型,这里我们发生了实际类型的转换。如果当前的内存没有绑定类型,那么我们就首次绑定类型,如果有它当前的原有类型,那么调用这个API,我们重新绑定为指定类型。
func testPointer(_ p: UnsafePointer<Int>) {
print(p[0], p[1])
}
let tuple = (10, 20)
withUnsafePointer(to: tuple) { (tuplePtr: UnsafePointer<(Int, Int)>) in
testPointer(UnsafeRawPointer(tuplePtr).bindMemory(to: Int.self, capacity: 1))
}
这里我们将UnsafePointer<(Int, Int)> 转换成了UnsafePointer 类型。
- withMemoryRebound(to: , capacity: )
withMemoryRebound就是用来临时更改我们的类型,减少代码复杂度。
func testPoint(_ p: UnsafePointer<Int8>) {
}
let UInt8Ptr = UnsafePointer<UInt8>.init(bitPattern: 10)
UInt8Ptr?.withMemoryRebound(to: Int8.self, capacity: 1, { (int8Ptr: UnsafePointer<Int8>) in
testPoint(int8Ptr)
})