Swift 指针&内存管理&Enum&optional

指针不是安全的

1.野指针。指针指向对象释放,指针变为野指针

2.指针超出内存空间边界访问。如数组越界

3.原⽣指针和类型指针的转换,会有数据丢失

指针类型

Swift中的指针分为两类,

类型指针: typed pointer 指定数据类型指针,

原⽣指针: raw pointer 未指定数据类型的指针


指针类型

原生指针

1.创建UnsafeMutableRawPointer.allocate

2.销毁指针deallocate()

3.储存值storeBytes(of: i, as: Int.self)

4.读取值load(fromByteOffset: i * MemoryLayout.stride, as: Int.self)

3.移动指针advanced(by: i * MemoryLayout.stride)

func demo1() {

      let p = UnsafeMutableRawPointer.allocate(byteCount: 4 * 8, alignment: 8)

      defer {

         print("32")

         p.deallocate()

      }

      

      for i in 0..<4 {

         p.advanced(by: i * MemoryLayout<Int>.stride).storeBytes(of: i, as: Int.self)

      }

      print(p)

      for i in 0..<4 {

         let value = p.load(fromByteOffset: i * MemoryLayout<Int>.stride, as: Int.self)

         print(value)

      }

   }

类型指针

第⼀种⽅式就是直接分配内存 

1.创建UnsafeMutablePointer<LGPerson>.allocate

2.销毁  p.deinitialize(count: 5) ->  p.deallocate()

3.储存值p[0]  = ...

4.读取值 pointee属性

let p = UnsafeMutablePointer<LGPerson>.allocate(capacity: 5)

      defer {

         p.deinitialize(count: 5)

         p.deallocate()

      }

      p[0] = LGPerson(age: 18, sex: true, married: true)

      p[1] = LGPerson(age: 19, sex: true, married: true)

      print(p)

      print(p.pointee)

第二种方式

通过已有变量获取 

通过withUnsafePointer(to: &age) { $0.pointee + 21} 获取当前变量的地址

    var age = 18

      age =withUnsafePointer(to: &age) { ptr in

         return ptr.pointee + 21

      }

      print(age)

指针绑定API

1.assumingMemoryBound(to:)  避免编译器类型检查

2.原生指针  bindMemory(to: capacity:) 更改内存绑定的类型。如果当前内存还没有类型绑定,则将⾸次绑定为该类型;否则重新绑定该类 型,并且内存中所有的值都会变成该类型

3.类型指针 withMemoryRebound(to: capacity: body:)指针使用过程中临时更改内存绑定类型

指针使用实例

1.解析类的数据结构

类的结构体指针内存布局

struct HeapObject {

   var metadata: UnsafeRawPointer

   var refCounted1: UInt32

   var refCounted2: UInt32

}

struct Metadata{

    var kind: Int

    var superClass: Any.Type

    var cacheData: (Int, Int)

    var data: Int

    var classFlags: Int32

    var instanceAddressPoint: UInt32

    var instanceSize: UInt32

    var instanceAlignmentMask: UInt16

    var reserved: UInt16

    var classSize: UInt32

    var classAddressPoint: UInt32

    var typeDescriptor: UnsafeMutableRawPointer

    var iVarDestroyer: UnsafeRawPointer

}

1. 获取实例的内存地址(原生指针) Unmanaged.passUnretained(t as AnyObject).toOpaque()

2.绑定具体类型(HeapObject)

let t = LGTeacher()

      let objRawPtr = Unmanaged.passUnretained(t as AnyObject).toOpaque()

      let objPtr = objRawPtr.bindMemory(to: HeapObject.self, capacity: MemoryLayout.stride(ofValue: t))

      let tMetaData = objPtr.pointee.metadata.bindMemory(to: Metadata.self, capacity: MemoryLayout<Metadata>.stride)

      print(MemoryLayout.stride(ofValue: t))

      print(objPtr.pointee)

      print(tMetaData.pointee)

      print("end")

2.UInt64 与指针转换

1.UInt64 -> 指针 UnsafePointer.init(bitPattern: Int(exactly: dataLoAddress) ?? 0)?

2.指针 -> UInt64 UInt64(bitPattern: Int64(Int(bitPattern: mhHeaderPtr)))

let mhHeaderPtr_IntRepresentation = UInt64(bitPattern: Int64(Int(bitPattern: mhHeaderPtr)))

    var dataLoAddress = mhHeaderPtr_IntRepresentation + offset

    var dataLoContent = UnsafePointer<UInt32>.init(bitPattern: Int(exactly: dataLoAddress) ?? 0)?.pointee

内存管理

Swift 中使⽤⾃动引⽤计数(ARC)机制来追踪和管理内存。

使用8字节存储当前的引⽤计数的。

weak 关键字,原来的 uint64_t 加上⼀个存储弱引⽤数的 uint32_t

1.正常情况InlineRefCountBits   strong RC + unowned RC + flags  64位

2.加weak  HeapObjectSideTableEntry  strong RC + unowned RC + weak RC + flags  64+32

HeapObject { 

    isa 

    InlineRefCounts { 

        atomic { 

            strong RC + unowned RC + flags 

        OR

        HeapObjectSideTableEntry* 

    } 

    } 

}

HeapObjectSideTableEntry { 

    SideTableRefCounts { 

        object pointer 

        atomic { 

        strong RC + unowned RC + weak RC + flags 

    } 

    } 

let t = LGTeacher()

let t1 = t

let t2 = t

print("end")

My Mac 调试的


引用计数

1. MetaData 内存地址

2.引用计数


二进制示意图

let t = LGTeacher(), strong RC + unowned RC + flags , strong RC 在33位是1, unowned RC在1位是1,flags在0位是1

Weak VS unowned 

如果两个对象的⽣命周期完全和对⽅没关系(其中⼀⽅什么时候赋值为nil,对对⽅都没影响),请⽤ weak 

如果你的代码能确保:其中⼀个对象销毁,另⼀个对象也要跟着销毁,这时候,可以(谨慎)⽤ unowned 

常见闭包循环引用

1. 类有个complateCallback 闭包

2.complateCallback 闭包 使用实例 t.age

解决方法: [unowned t] 

let t = LGTeacher()

      t.complateCallback = { [unowned t] in

         t.age += 1

      }

闭包循环引用

不加unowned 或 weak ,不执行deinit{} 方法的

加入unowned 或 weak ,执行deinit{} 方法的

捕获列表

      var age = 0

      var height = 0.0

      let closure = {[age] in

         print(age)

         print(height)

      }

      age =10

      height =1.88

      closure()

输出:age =  0  height = 1.88

[age] 捕获闭包之前的age值

height没有出现在捕获列表中,height值是闭包调用前height的值

Enum

内存大小

MemoryLayout>.size内存实际大小

MemoryLayout.stride内存步长

MemoryLayout.alignment 字节对齐

enum Weak: Int {

   case MONDAY = 0

   case TUEDAY

   case WEDDAY

   case THUDAY

   case FRIDAY

   case SATDAY

   case SUNDAY

}

1. enum 的原始值rawValue,需要明确原始值类型

Weak.MONDAY.rawValue

Weak枚举内存大小 1字节

var a = Weak.MONDAY

MemoryLayout.size(ofValue: a)  1

MemoryLayout.stride(ofValue: a)  1

enum LGEnum {

//  case test_one(Bool)

    case test_two(Int)

   case test_three

   case test_four

}

MemoryLayout.size  9

MemoryLayout.stride 16

enum 内存大小

关联值 所有参数内存大小 + 1字节

 sizeof(Int) * 3 + sizeof(rawVlaue)

关键值indirect

enum List{

    case end

   indirect case node(Element, next: List<Element>)

}

enum 前面加indirect,创建List枚举类型,调用swift_allocObject方法

 indirect case node,是node时才调用swift_allocObject方法,end不调用的

Optional是一个枚举

enum MyOptional {

   case some(Value)

   case none

}

你可能感兴趣的:(Swift 指针&内存管理&Enum&optional)