指针
swift中的指针分为两类,typed pointer:指定数据类型指针,其表示为UnsafePointer<T>,raw pointer未指定数据类型的指针(原生指针),其表示为UnsafePointer。
Swift中的指针和OC中的指针的对应关系如下:
| Swift | Objective-C | 说明 |
|---|---|---|
| unsafePointer< T > | const T * | 指针及所指向的内容都不可变 |
| unsafeMutablePointer | T * | 指针及所指向的内容均可变 |
| unsafeRawPointer | const void * | 指针指向未知类型 |
| unsafeMutableRawPointer | void * | 指针指向未知类型 |
原生指针(raw pointer)
对于原生指针的操作,我们可以通过以下代码来操作raw pointer
// 1
let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)
for i in 0..<4 {
// 2
p.advanced(by: i * 8).storeBytes(of: i, as: Int.self)
}
for i in 0..<4 {
// 3
let value = p.load(fromByteOffset: i * 8, as: Int.self)
print("index\(i), value:\(value)")
}
// 4
p.deallocate()
- 1,分配了 32 字节大小的空间,8字节对齐。
- 2,每次移动 i * 8, 以整型的格式向该内存中存数据。
- 3,每次偏移 i * 8,以整型结构读取内存值。
- 4,手动管理内存空间,需要手动释放。
类型指针 (typed pointer)
类型指针可以指定该指针对应的数据类型,通过类型指针我们可以向内存中,以对象 的形式存储。
// 1
struct Person {
var age = 18
var height = 180
}
// 2
let ptr = UnsafeMutablePointer<Person>.allocate(capacity: 2)
// 3
ptr.initialize(to: Person())
// 4
ptr.advanced(by: 1).initialize(to: Person(age: 17, height: 170))
// 5
print(ptr[0])
// 6
print(ptr[1])
// 5
print(ptr.pointee)
// 6
print(ptr.successor().pointee)
// 7
ptr.deinitialize(count: 2)
// 8
ptr.deallocate()
- 1,声明一个
Person结构体。 - 2,使用 类型指针 申请 2 个 Person 结构体大小的内存空间。
- 3,4,向该内存中写入两个 Person 结构体,在这里类型已经确定,前进1个该类型空间大小的空间。
- 5,通过
ptr[0]或 ptr.pointee的形式,在内存中读取第一个对象。 - 6,通过
ptr[1]的形式,读取第二个对象,ptr.successor()获取下一个对象。 - 7,8,对申请的空间进行回收。
将原生指针转化为类型指针
我们声明一个函数
func testPointer(_ p: UnsafeRawPointer) {
// 1
let t = p.assumingMemoryBound(to: Int.self)
}
- 1,
假定p指针已经绑定了Int类型的数据。 我们可以看到此时变量t已经变成了UnsafePointer<Int>类型。
绑定自定义结构
对象swift中的实例对象和类对象的结构,在Swift对象一文中进行了探讨,接下来,我们将自定义swift对象结构,并和内存指针进行绑定。
自定义HeapObject
我们通过操控指针的形式,将一段内存空间绑定到我们自定义的结构体中。我们模仿系统的HeapObject结构自定义如下结构体:
struct CusHeapObject {
var kind: UnsafeRawPointer
var strongRef: UInt32
var unownedRef: UInt32
}
class Person {
var age = 18
}
我们将 Person类的结构绑定到 我们自定义的CusHeapObject中
var p = Person()
// 1
let ptr = Unmanaged.passUnretained(p as AnyObject).toOpaque()
// 2
let heapObject = ptr.bindMemory(to: CusHeapObject.self, capacity: 1)
// 3
print(heapObject.pointee)
我们看下输出结果
CusHeapObject(kind: 0x0000000100008168, strongRef: 3, unownedRef: 0)
- 1,获取 变量p 的指针,为
UnsafeMutableRawPointer类型。 - 2,将ptr指针指向的空间和结构体
CusHeapObject进行绑定。 - 3,输入指针引用的实例对象。
自定义swift类对象
我们自定义一个swift类对象:
struct cus_swift_class {
var kind: UnsafeRawPointer
var superClass: UnsafeRawPointer
// 1
var cacheData1: UnsafeRawPointer
var chcheData2: UnsafeRawPointer
var data: UnsafeRawPointer
var flags: UInt32
var instanceAddressOffset: UInt32
var instanceSize: UInt32
var flinstanceAlignMask: UInt16
var reserved: UInt16
var classSize: UInt32
var description: UnsafeRawPointer
}
- 1,
swift_class中的cacheData为元组结构,共 16 字节,在这里我们使用两个指针来表示。 同样我们对对象的指针进行绑定
var p = Person()
// 1
let ptr = Unmanaged.passUnretained(p as AnyObject).toOpaque()
// 2
let heapObject = ptr.bindMemory(to: CusHeapObject.self, capacity: 1)
// 3
let metaPtr = heapObject.pointee.kind.bindMemory(to: cus_swift_class.self, capacity: 1)
print(metaPtr.pointee)
输出结果:
// cus_swift_class(kind: 0x0000000100008140, superClass: 0x00007fff8896b8f8, cacheData1: 0x00007fff201e9af0, chcheData2: 0x0000802000000000,
// data: 0x0000000100758822, flags: 2, instanceAddressOffset: 0, instanceSize: 24, flinstanceAlignMask: 7, reserved: 0, classSize: 136, description: 0x0000000100003c40)
- 1,获取变量 p 的指针地址ptr。
- 2,将ptr指针绑定到我们
自定义的实例对象结构上。 - 3,将
heapObject:CusHeapObject的kind指向cus_swift_class。
这样我们就把p对象绑定到了我们自定义的类对象上面,为什么能够将其kind指针进行重绑定呢?因为指针所指向的内存空间和我们自定义的结构是一致的,我们才能成功的将指针和自定义结构体进行绑定。
总结
我们对swift中的原生指针和类型指针做了一个简单的了解,并通过操作指针来对swift 对象进行自定义类型绑定。