Swift中指针

Swift中有4个指针类型:UnsafePointerUnsafeMutablePointerUnsafeRawPointerUnsafeMutableRawPointer,通过指针可以直接修改指向的内存数据,下面简单介绍下它们的几个常见用法。

一、从已有的变量获取指针
  1. 获取指向变量或者指向对象的指针、读写指向变量的值的方式如下:
var age = 10

// 通过withUnsafeXXXXPointer创建指向变量或对象的指针
func testGetPointer() {
    // 1.指向值类型变量时
    var ptr1 = withUnsafePointer(to: &age, { $0 })
    var ptr2 = withUnsafeMutablePointer(to: &age, { $0 })
//    ptr1.pointee = 15 // ptr1不可变,这里报错
    ptr2.pointee = 20
    print("ptr1=\(ptr1.pointee), ptr2=\(ptr2.pointee)") // 都是20
    // 使用原始指针
    var ptr3 = withUnsafePointer(to: &age, { UnsafeRawPointer($0) })
    var ptr4 = withUnsafeMutablePointer(to: &age, { UnsafeMutableRawPointer($0) })
    ptr4.storeBytes(of: 50, as: Int.self)
    print("ptr3=\(ptr3.load(as: Int.self)), ptr4=\(ptr4.load(as: Int.self))") // 都是50
    
    // 2.指向对象时
    var hba = HBA(no: "no119", name: "name120")
    let ptr5 = withUnsafePointer(to: &hba, { $0 })
    let ptr6 = withUnsafeMutablePointer(to: &hba, { $0 })
    ptr6.pointee.no = "no911"
    print("no=\(ptr5.pointee.no),name=\(ptr5.pointee.name)") // no=no911,name=name120
    
    // 原始指针
    var ptr7 = withUnsafePointer(to: &hba, { UnsafeRawPointer($0) })
//    var ptr8 = withUnsafeMutablePointer(to: &hba, { UnsafeMutableRawPointer($0) })
    // ptr7、ptr8的值是hba指针的地址值,要访问到hba对象的堆空间地址值还需要如下操作
    // 根据bitPattern参数(堆空间地址)初始化一个指针
    var heapPtr = UnsafeRawPointer(bitPattern: ptr7.load(as: UInt.self))!
    // 将这个堆空间指针转换类型后就可以很方便得访问属性
    let hba2 = unsafeBitCast(heapPtr, to: HBA.self)
    print("hba2==", hba2.name)
}
  1. 作为函数参数时,可变类型的指针UnsafeMutablePointerUnsafeRawPointer与inout参数效果类似,都可以修改指向的值,不同之处在于inout参数可以直接改。
func testPointer()  {
    useinout(&age)
    usePointer1(&age)
    usePointer2(&age)
    usePointer3(&age)
    usePointer4(&age)
}

func useinout(_ ptr: inout Int) {
    print("inout-ptr前:\(ptr)")
    ptr = 90
    print("inout-ptr后:\(ptr)")
}

// UnsafePointer不可修改指向内存
func usePointer1(_ ptr: UnsafePointer<Int>) { // 相当于const int *
    print("ptr.pointee:\(ptr.pointee)")
}

// UnsafeMutablePointer可修改指向内容
func usePointer2(_ ptr: UnsafeMutablePointer<Int>) {// 相当于int *
    print("ptr.pointee前\(ptr.pointee)")
    ptr.pointee = 20
    print("ptr.pointee后\(ptr.pointee)")
}

// 不可修改的原始指针
func usePointer3(_ rawptr: UnsafeRawPointer) { // 相当于const void *
    print("rawptr:\(rawptr.load(as: Int.self))")
}

// UnsafeMutableRawPointer可修改指向内容的原始指针
func usePointer4(_ rawptr: UnsafeMutableRawPointer) {// 相当于void *
    print("rawptr.pointee前\(rawptr.load(as: Int.self))")
    rawptr.storeBytes(of: 19, as: Int.self)
    print("rawptr.pointee后\(rawptr.load(as: Int.self))") // 19
}
二、创建新的指针

可通过4种方式创建新的指针:

  • UnsafeRawPointer(bitPattern: 内存地址)
  • malloc(字节数)
  • 可变原始指针,UnsafeMutableRawPointer.allocate(byteCount:字节数, alignment: 1)
  • 可变指针,UnsafeMutablePointer<泛型类型>.allocate(capacity: 泛型类型个数)
// 新创建指针
func testNewPointer() {
    // 1.直接传内存地址来创建一个原始指针
    var ptr = UnsafeRawPointer(bitPattern: 0x100001234)
    // 2.通过malloc来创建一个可变原始指针(可以存值)
    var ptr2 = malloc(16)
    // 修改
    ptr2?.storeBytes(of: 118, as: Int.self)
    ptr2?.storeBytes(of: 220, toByteOffset: 8, as: Int.self)
    // 读取
    print((ptr2?.load(as: Int.self))!) // 118
    print((ptr2?.load(fromByteOffset: 8, as: Int.self))!) //220
    
    // 3.通过可变原始指针分配、修改、读取内存
    var ptr3 = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
    ptr3.storeBytes(of: 30, as: Int.self)
    ptr3.advanced(by: 8).storeBytes(of: 33, as: Int.self)
    
    print(ptr3.load(as: Int.self)) // 30
    print(ptr3.advanced(by: 8).load(as: Int.self)) //33
    
    // 4.通过可变指针分配、修改、读取内存
    var ptr4 = UnsafeMutablePointer<Int>.allocate(capacity: 3)
    ptr4.initialize(to: 11)
    ptr4.successor().initialize(to: 22)
    ptr4.successor().successor().initialize(to: 33)
    
    print("第1个int = \(ptr4.pointee), 第2个int = \((ptr4 + 1).pointee), 第3个int = \((ptr4 + 2).pointee)")
    print("第1个int = \(ptr4[0]), 第2个int = \(ptr4[1]), 第3个int = \(ptr4[2])")
    
    ptr4.deinitialize(count: 3)
    ptr4.deallocate()
}
三、指针类型转换

上述指针类型之间可以进行转换,如下:

// 指针之间的转换
func testPointerTransfer() {
    let ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
    // 1. 通过assumingMemoryBound来转换
    ptr.assumingMemoryBound(to: Int.self).pointee = 11
    (ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22
    
    // 2.通过unsafeBitCast进行忽略类型的强制转换
    // 转换为UnsafePointer<Int>类型后通过pointee访问
    let ptr_trannsfer = unsafeBitCast(ptr, to: UnsafePointer<Int>.self)
    print(ptr_trannsfer.pointee)
    let ptr_trannsfer2 = unsafeBitCast(ptr + 8, to: UnsafePointer<Double>.self)
    print(ptr_trannsfer2.pointee)
    
    // 3.UnsafeMutableRawPointer可以通过bindMemory方法转换为UnsafeMutablePointer
    let ptr222 = (ptr + 8).bindMemory(to: Double.self, capacity: 1)
    ptr222.pointee = 33.0
    print(ptr222.pointee)
    
    ptr.deallocate()
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章