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<Int>.stride, as: Int.self)

3.移动指针advanced(by: i * MemoryLayout<Int>.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<UInt32>.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<InlineRefCountBits> { 

            strong RC + unowned RC + flags 

        OR

        HeapObjectSideTableEntry* 

    } 

    } 

}

HeapObjectSideTableEntry { 

    SideTableRefCounts { 

        object pointer 

        atomic<SideTableRefCountBits> { 

        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<Int>.size内存实际大小

MemoryLayout<LGPerson>.stride内存步长

MemoryLayout<LGPerson>.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<LGEnum>.size  9

MemoryLayout<LGEnum>.stride 16

enum 内存大小

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

 sizeof(Int) * 3 + sizeof(rawVlaue)

关键值indirect

enum List<Element>{

    case end

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

}

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

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

Optional是一个枚举

enum MyOptional<Value> {

   case some(Value)

   case none

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容