小言_互联网的博客

5、Swift指针

327人阅读  评论(0)

1.Swift中指针分为两类:

  •    Raw Pointer 未指定数据类型指针(原生指针)--> UnsafeRawPointer
  •    Type Pointer 指定数据类型指针 --> UnsafePointer
  • 下面我们来看Swift中的指针和OC中指针的对应关系

  
  1. Swift Object- C 说明
  2. UnsafePointer< T> const T* 指针及所指向的内容都不可变
  3. UnsafeMutablePointer T * 指针及其所指向的内存内容均可变
  4. UnsafeRawPointer const void * 指针指向未知类型
  5. UnsafeMutableRawPointer void * 指针指向未知类型

2.原生指针的使用(UnsafeMutableRawPointer)

  • 假设我们想在内存中存储连续4个整型的数据,我们如何使用Raw Pointer来实现呢?
    • 原生指针的使用是需要我们对其内存进行手动管理的、在使用的时候创建、使用完毕后需要释放allocate和deallocate成对出现。
    • 分配指定大小的内存空间、规定对齐方式为
    • advanced移动当前存储值的内存大小,storeBytes存储我们当前的数据
    • load加载相对于我们当前指针首地址的偏移

  
  1. //分配32字节大小的内存空间、对其方式为:8字节对齐
  2. let p = UnsafeMutableRawPointer.allocate(byteCount: 32, alignment: 8)
  3. for i in 0..< 4{
  4. //advanced代表当前 p 前进的步长,对于RawPointer来说,我们需要移动的是当前存储值的内存大小,既MemoryLayout.stride
  5.     //storeBytes:这里就是存储我们当前的数据,这里需要指定当前数据的类型
  6. p.advanced(by: i* 8).storeBytes(of: i+ 1, as: Int. self)
  7. }
  8. for i in 0..< 4{
  9. //load 表示加载,fromBytesOffset: 是相对于我们当前p 的首地址的偏移
  10.     let value = p.load(fromByteOffset: i* 8, as: Int. self)
  11.     print( "index\(i),value\(value)")
  12. }
  13. p.deallocate()
  • 其中UnsafeMutableRawPointer的allocate方法底层实现为 :(在源码 swift/stdlib/public/core/UnsafeRawPointer.swift 搜索 "allocate(" )
    • 匹配对齐方式
    • 通过Builtin.allocRaw创建UnsafeMutableRawPointer对象

  
  1. @inlinable
  2. public static func allocate(
  3. byteCount: Int, alignment: Int
  4. ) -> UnsafeMutableRawPointer {
  5. var alignment = alignment //匹配当前对齐方式
  6. if alignment <= _minAllocationAlignment() {
  7. alignment = 0
  8. } //Builtin:Swift中的标准模块(本质上编译过程中会匹配LLVM中的类型和方法、在当前调用过程中减少Swift运行负担)
  9. return UnsafeMutableRawPointer( Builtin.allocRaw(
  10. byteCount._builtinWordValue, alignment._builtinWordValue))
  11. }

3.范型指针的使用(UnsafePointer):确定类型的指针

  • 如何获取变量的地址?
    • withUnsafeMutablePointer(to: T){$0}
    • 获取上述表达式的返回结果既为当前指针
    • x/8g输出既得到当前变量地址

  
  1. var age = 18
  2. withUnsafeMutablePointer(to: &age){$ 0} //单一表达式:$0与return ptr表达式性质一样
  3. let b = withUnsafePointer(to: &age) { (ptr) in return ptr }
  4. //使用pointee来访问当前指针变量值
  5. print(b.pointee) //18

  • 如何通过指针改变当前变量值?
    • 不可变指针间接修改变量值
        • withUnsafePointer的返回值是 UnsafePointer,意味着我们不能直接修改值(如我们C语言中的 char *p = "HS")
        • C中我们使用 *p 来访问我们的 "HS", 顾在这里我们使用 ptr.pointee来访问age的值,从而修改age值。

  
  1. age = withUnsafePointer(to: &age, { (ptr) in
  2.     return ptr.pointee + 12 //Int整形值 30
  3. })
  • 可变指针 直接修改变量值
    • 使用withUnsafeMutablePointer来直接修改我们的变量值、返回变量的结果取决于闭包表达式中的操作
    • 使用var name:String = "Holo"在闭包表达式中做ptr.pointee += "thurian" 操作会得到 name = "Holothurian"

  
  1. withUnsafeMutablePointer(to: &age) { ptr in
  2.     ptr.pointee += 6
  3. }
  4. print(age) //36

 

  • 指定数据类型指针(Type Pointer):UnsafeMutablePointer

  
  1. var age = 10
  2. //1、capacity:容量大小,当前的大小为 1 * 8字节
  3. let ptr = UnsafeMutablePointer< Int>.allocate(capacity: 1)
  4. //2、初始化当前的UnsafeMutablePointer<Int> 指针
  5. ptr.initialize(to: age)
  6. age = ptr.pointee + 12 //age = 22
  7. //3、下面两个成对调用,内存管理
  8. ptr.deinitialize( count: 1)
  9. ptr.deallocate()
  • 分析指定结构体类型指针

  
  1. struct LGTeacher {
  2.     var age = 10
  3.     var height = 1.88
  4. }
  5. var t = LGTeacher()
  6. let ptt = UnsafeMutablePointer< LGTeacher>.allocate(capacity: 2)
  7. ptt.initialize(to: LGTeacher()) //初始化完成
  8. //1、可以通过该种方式进行访问下一块内存空间
  9. ptt.advanced(by: 1).initialize(to: LGTeacher(age: 20, height: 1.88))
  10. print(ptt[ 0]) //LGTeacher(age: 10, height: 1.88)
  11. print(ptt[ 1]) //LGTeacher(age: 20, height: 1.99)
  12. //2、通过访问ptt.pointee获取首地址值
  13. print(ptt.pointee) //LGTeacher(age: 10, height: 1.88)
  14. print((ptt+ 1).pointee) //LGTeacher(age: 20, height: 1.99)
  15. //3、通过successor访问 ;successor往前移动8字节
  16. print(ptt.successor().pointee) //LGTeacher(age: 20, height: 1.99)
  17. ptt.deinitialize( count: 2)
  18. ptt.deallocate()

案例练习:将HSTeacher创建的实例变量绑定到结构体HeapObject内存中


  
  1. struct HeapObject {
  2.     var kind: UnsafeRawPointer
  3.     var strongref: UInt32
  4.     var unownedRef: UInt32
  5. }
  6. class HSTeacher{
  7.     var age = 19
  8. }
  • 首先获取到实例变量的地址
  • 然后使用Unmanaged获取非托管实例对象的指针
  • 最后将获取的实例变量的指针绑定到具体类型;

  
  1. var temp = HSTeacher()
  2. //Unmanaged相当于OC 和CF交互方式中, __bridge 所有权的转换
  3. //create,copy使用retained; opaque不透明
  4. //passUnretained不增加引用计数、passRetained增加引用计数
  5. //CFRealse //passUnretained申明非托管对象
  6. let ptrrr = Unmanaged.passUnretained(temp as AnyObject).toOpaque() //不需要获得对象的所有权
  7. let ptrl = Unmanaged.passRetained(temp) //获得对象所有权
  8. print(ptrrr) //0x000000010070d1f0
  9. print(ptrl) //Unmanaged<HSTeacher>(_value: SwiftPointer.HSTeacher)
  10. //当前内存指针绑定到具体类型:返回 UnsafeMutablePointer
  11. let headObject = ptrrr.bindMemory(to: HeapObject. self, capacity: 1)
  12. let a = headObject.pointee.kind //0x000000010000c308
  13. let s = headObject.pointee.strongref //2
  14. let k = headObject.pointee.unownedRef //2
  • 如何将HeapObject中的kind绑定到我们的类的结构内存中?
    • 通过类的结构分析我们得到类的结构如下:

  
  1. struct hs_swift_class {
  2.     var kind: UnsafeRawPointer
  3.     var superClass: UnsafeRawPointer
  4.     var cachedata1: UnsafeRawPointer
  5.     var cachedata2: UnsafeRawPointer
  6.     var data: UnsafeRawPointer
  7.     var flags: UInt32
  8.     var instanceAddressOffset: UInt32
  9.     var instanceSize: UInt32
  10.     var flinstanceAlignMask: UInt32
  11.     var reserved: UInt16
  12.     var classSize: UInt32
  13.     var classAddressOffset: UInt32
  14.     var description: UnsafeRawPointer
  15. }
  • 那么我们进行绑定如下:
    • bindMemory(to: Capacity:) 更改内存绑定的类型,如果之前没有绑定,那么就是⾸次绑定;如果绑定过了,会被重新绑定为该类型。

  
  1. var temp = HSTeacher()
  2. let ptr = Unmanaged.passUnretained(temp as AnyObject).toOpaque()
  3. let headObject = ptr.bindMemory(to: HeapObject. self, capacity: 1)
  4. let metaPtr = headObject.pointee.kind.bindMemory(to: hs_swift_class. self, capacity: 1)
  • 使用assumingMemoryBound 案例1: 元组指针类型转换
    • assumingMemoryBound:假定内存绑定、告诉编译器当前绑定的类型、不需要进行编译检查

  
  1. var tul = ( 10, 20)
  2. withUnsafePointer(to: &tul) { (tulPtr: UnsafePointer<( Int, Int)>) in
  3. assuminMemoryBound 假定内存绑定、不需要进行编译检查
  4.     testPointer( UnsafeRawPointer(tulPtr).assumingMemoryBound(to: Int. self))
  5. }
  6. func testPointer(_ p : UnsafePointer<Int>){
  7.     print(p)
  8.     print(p.pointee) //输出首地址值:10
  9.     print((p[ 0],p[ 1])) //(10,20)
  10.     /*
  11.      x/8g 0x000000010000c4b0
  12.     0x10000c4b0: 0x000000000000000a 0x0000000000000014
  13.      */
  14. }

 

案例2: 使用assumingMemoryBound 获取结构体的属性的指针


  
  1. struct HeapObject {
  2.     var strongref = 10
  3.     var unownedRef = 20
  4. }
  5. var t = HeapObject()
  6. withUnsafePointer(to: &t) { (ptr: UnsafePointer< HeapObject>)  in
  7.     let strongRefPtr = UnsafeRawPointer(ptr) + MemoryLayout< HeapObject>.offset(of: \ HeapObject.strongref)!
  8.     testPointer(strongRefPtr.assumingMemoryBound(to: Int. self))
  9. }
  • withMemoryRebound:临时更改内存绑定类型、出了作用域将还原为原有类型。
    • 案例使用:

  
  1. struct HeapObjecter{
  2.     var strongref = 15
  3.     var unownedRef = 25
  4. }
  5. var tt = HeapObjecter()
  6. withUnsafePointer(to: &tt) { (ptr: UnsafePointer< HeapObjecter>) in
  7.     ptr.withMemoryRebound(to: Int. self, capacity: 1) { (temp) in
  8.         testPointer(temp)
  9.     }
  10. }
  11. func testPointer(_ p:UnsafePointer<Int>) {
  12.     print(p)
  13.     print(p.pointee)
  14.     print((p[ 0],p[ 1]))
  15. }

 

 

 

 


转载:https://blog.csdn.net/SharkToping/article/details/117253587
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场