pointer - ShenYj/ShenYj.github.io GitHub Wiki
Swift中的指针分为两类
-
typed pointer
指定数据类型指针 ->UnsafePointer<T>
-
raw pointer
未指定数据类型的指针(原生指针) ->UnsafeRawPointer
Swift | Object-C | 说明 |
---|---|---|
unsafePointer<T> | const T * | 指针机所指向的内容都不可变 |
unsafeMutablePointer<T> | T * | 指针及其所指向的内存内容均可变 |
unsafeRawPointer | const void * | 指针指向未知类型 |
unsafeMutableRawPointer | void * | 指针指向未知类型 |
let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)
for i in 0..<4 {
p.advanced(by: i * 8).storeBytes(of: i, as: Int.self)
}
for i in 0..<4 {
let value = p.load(fromByteOffset: i * 8, as: Int.self)
print("index:\(i) - value:\(value)")
}
p.deallocate()
index:0 - value:0
index:1 - value:1
index:2 - value:2
index:3 - value:3
advanced
代表当前 p 前进的步长,对于RawPointer
来说,我们需要移动的是当前存储值得内存大小即,MemoryLayout.stride
storeBytes
: 这里就是存储我们当前的数据,这里需要制定我们当前数据的类型load(fromBytesOffe:)
是相对于我们当前 p 的首地址的偏移
-
基于给定参数的指针
var age = 10 let p: UnsafePointer<Int> = withUnsafePointer(to: &age) { $0 } print(p.pointee) // 10
var age = 10 let p: Int = withUnsafePointer(to: &age) { $0.pointee + 12 } print(p) // 22
var age = 10 withUnsafeMutablePointer(to: &age) { $0.pointee = 20 } print(age) // 20
var age = 10 let ptr = UnsafeMutablePointer<Int>.allocate(capacity: 1) ptr.initialize(to: age) ptr.deinitialize(count: 1) ptr.deallocate() print(ptr.pointee)
-
实例化一个给定类型的指针
struct Person { var age = 10 var height = 1.85 } let p = UnsafeMutablePointer<Person>.allocate(capacity: 2) p.initialize(to: Person()) p.advanced(by: 1) // 等同于 p.successor() .initialize(to: Person(age: 20, height: 1.75)) print("++++++++") print(p[0]) // Person(age: 10, height: 1.85) print(p[1]) // Person(age: 20, height: 2.78134232336082e-309) print("--------") print(p.pointee) // Person(age: 10, height: 1.85) print((p + 1).pointee) // Person(age: 20, height: 1.75) print(p.successor().pointee) // Person(age: 20, height: 1.75) p.deinitialize(count: 2) p.deallocate()
withUnsafePointer
的返回值是unSafePointer
,意味着我们不能直接修改值, 如果我们想要直接修改当前Pointer.pointee
的值,那么使用withUnsafeMutablePointer
; 都是Swift提供的简写的API,这里注意当前尾随闭包的写法区分下
UnsafeRawPointer
的第一段示例代码中的offset
,原生指针不明确类型,因此指定了每次offset
是多少, 在这段示例中,已经明确了Person
这个结构体类型, 因此只需要传递当前类型指针下的offset
即可,这一点和传统C 指针的方式一样
上面手动管理内存的指针使用方式比较繁琐
import Foundation
struct HeapObject {
var kind: UnsafeRawPointer
var strongref: UInt32
var unwonedRef: UInt32
}
// 根据每个字段大小模拟的swift 结构
struct swift_class {
var King: UnsafeRawPointer
var superClass: UnsafeRawPointer
var cachedata1: UnsafeRawPointer
var cachedata2: UnsafeRawPointer
var data: UnsafeRawPointer
var flags: UInt32
var instanceAddressOffset: UInt32
var instanceSize: UInt32
var instanceAlignMask: UInt16
var reserved: UInt16
var classSize: UInt32
var classAddressOffset: UInt32
var description: UnsafeRawPointer
}
class Person {
var age = 10
var height = 1.85
}
var person = Person()
// 托管指针, 帮助我们完成内存管理, 类似于OC与CF的 __bridge
let pointer = Unmanaged.passUnretained(person as AnyObject).toOpaque()
// 将内存绑定到指定的类型
let heapPointer: UnsafeMutablePointer<HeapObject> = pointer.bindMemory(to: HeapObject.self, capacity: 1)
// 绑定后就能直接访问 `HeapObject` 的成员变量了, 比如: heapPointer.pointee.kind、heapPointer.pointee.strongref
print(heapPointer.pointee) // HeapObject(kind: 0x0000000103ecb190, strongref: 3, unwonedRef: 0)
// 将属性 kind 的内存在绑定给 swift_class 类型
let metaDataPointer = heapPointer.pointee.kind.bindMemory(to: swift_class.self, capacity: 1)
print(metaDataPointer.pointee)
// swift_class(King: 0x00000001006e02a0, superClass: 0x00007fff86baff70, cachedata1: 0x0000600001721680, cachedata2: 0x0001802800000007, data: 0x0000600003924f02, flags: 2, instanceAddressOffset: 0, instanceSize: 32, instanceAlignMask: 7, reserved: 0, classSize: 168, classAddressOffset: 16, description: 0x00000001006e0578)
如果有指向已绑定到指定类型的内存的原始指针,请使用此方法
func assumingMemoryBound<T>(to: T.Type) -> UnsafePointer<T>
从该指针开始的内存必须绑定到类型T。如果内存尚未绑定到T,则通过返回的指针访问内存是未定义的。要将内存绑定到T,请使用bindMemory(to:capacity:)
而不是此方法。
var tuple = (10, 20)
withUnsafePointer(to: &tuple) { (tuplePointer: UnsafePointer<(Int, Int)>) in
testPointer(UnsafeRawPointer(tuplePointer).assumingMemoryBound(to: Int.self))
}
func testPointer(_ p : UnsafePointer<Int>) {
print(p.pointee) // 10
}
withMemoryRebound
: 临时更改内存绑定类型bindMemory(to: Capacity:)
: 更改内存绑定的累心个,如果之前没有绑定,那么就是首次绑定;如果绑定过了,会被重新绑定为该类型assumingMemoryBound
: 假定内存绑定,这里是告诉编译器(相当于忽略检查)