• Swift中的内存访问冲突、指针、局部作用域


     内存访问冲突(Conflicting Access to Memory)

    1、内存访问冲突会在两个访问满足以下条件时发生:

    • 至少一个是写入操作
    • 它们访问的是同一块内存
    • 它们的访问时间重叠(比如在同一个函数内)
    1. //无内存访问冲突
    2. func plus(_ num: inout Int) -> Int {
    3. num + 1
    4. }
    5. var number = 1
    6. number = plus(&number)
    7. //有内存访问冲突
    8. var step = 1
    9. func increment(_ num: inout Int) {
    10. num += step //error
    11. }
    12. increment(&step)
    13. //解决内存访问冲突
    14. var copyOfStep = step
    15. increment(&copyOfStep)
    16. step = copyOfStep

    2、如果下面的条件可以满足 ,就说明重叠访问结构体的属性是安全的

    • 你只访问实例存储属性,不是计算属性或者类属性
    • 结构体是局部变量而非全局变量
    • 结构体要么没有被闭包捕获要么只被非逃逸闭包捕获

    指针

    1、Swift中也有专门的指针类型,这些都被定性为“Unsafe”(不安全的),常见的有以下4中类型

    • UnsafePointer 类似于const Pointee *
    • UnsafeMutablePointer 类似于Pointee *
    • UnsafeRawPointer 类似于const void *
    • UnsafeMutableRawPointer 类似于 void *
    1. var age = 10
    2. func test1(_ ptr: UnsafeMutablePointer<Int>) {
    3. ptr.pointee = 20
    4. print("test1", ptr.pointee)
    5. }
    6. func test2(_ ptr: UnsafePointer<Int>) {
    7. print("test2", ptr.pointee);
    8. }
    9. func test4(_ ptr: UnsafeMutableRawPointer) {
    10. ptr.storeBytes(of: 30, as: Int.self)
    11. }
    12. func test5(_ ptr: UnsafeRawPointer) {
    13. print("test5", ptr.load(as: Int.self))
    14. }

    指针的应用示例 

    1. //OC -> BOOL *
    2. //Swift -> UnsafeMutablePointer<ObjCBool>
    3. var arr = NSArray(objects: 11, 22, 33, 44)
    4. arr.enumerateObjects { (element, idx, stop) in
    5. print(idx, element)
    6. if idx == 2 {
    7. stop.pointee = true
    8. }
    9. }

    获得指向某个变量的指针

    1. var age = 10
    2. var ptr1 = withUnsafeMutablePointer(to: &age) {
    3. $0
    4. }
    5. var ptr2 = withUnsafePointer(to: &age) {
    6. $0
    7. }
    8. ptr1.pointee = 22
    9. print(ptr2.pointee) // 22
    10. print(age) // 22
    11. var ptr3 = withUnsafeMutablePointer(to: &age) {
    12. UnsafeMutableRawPointer($0)
    13. }
    14. var ptr4 = withUnsafePointer(to: &age) {
    15. UnsafeRawPointer($0)
    16. }
    17. ptr3.storeBytes(of: 33, as: Int.self)
    18. print(ptr4.load(as: Int.self)) // 33
    19. print(age) // 33

    获得指向堆空间实例的指针

    1. class Person {
    2. var age: Int
    3. init(age: Int) {
    4. self.age = age
    5. }
    6. }
    7. var person = Person(age: 21)
    8. var ptr1 = withUnsafePointer(to: &person) {
    9. UnsafeRawPointer($0)
    10. }
    11. var personObjAddress = ptr1.load(as: UInt.self)
    12. var ptr2 = UnsafeMutableRawPointer(bitPattern: personObjAddress)
    13. //下面这种方式和上面的实现效果相同
    14. //var ptr = unsafeBitCast(person, to: UnsafeRawPointer.self)

    通过指针我们可以很容易的获取内存中变量的地址值,方便窥探底层做的事情。 

     创建指针

    1. var ptr = malloc(16)
    2. ptr?.storeBytes(of: 10, as: Int.self)
    3. ptr?.storeBytes(of: 20, toByteOffset: 8, as: Int.self)
    4. print(ptr?.load(as: Int.self)) // 10
    5. print(ptr?.load(fromByteOffset: 8, as: Int.self)) // 20
    6. free(ptr)
    1. var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
    2. ptr.storeBytes(of: 11, as: Int.self)
    3. ptr.advanced(by: 8).storeBytes(of: 22, as: Int.self)
    4. print(ptr.load(as: Int.self)) // 11
    5. print(ptr.advanced(by: 8).load(as: Int.self)) // 22
    6. ptr.deallocate()
    1. var ptr = UnsafeMutablePointer<Int>.allocate(capacity: 2)
    2. ptr.initialize(to: 10)
    3. ptr.successor().initialize(to: 20)
    4. print(ptr.pointee)
    5. print((ptr + 1).pointee)
    6. print(ptr.pointee)
    7. print(ptr.successor().pointee)
    8. print(ptr[0])
    9. print(ptr[1])
    10. ptr.deinitialize(count: 2)
    11. ptr.deallocate()

    测试内存的释放:

    1. class Person {
    2. var age: Int
    3. var name: String
    4. init(age: Int, name: String) {
    5. self.age = age
    6. self.name = name
    7. }
    8. deinit {
    9. print(name, "deinit")
    10. }
    11. }
    12. var ptr = UnsafeMutablePointer<Person>.allocate(capacity: 3)
    13. ptr.initialize(to: Person(age: 20, name: "Jack"))
    14. (ptr + 1).initialize(to: Person(age: 21, name: "Rose"))
    15. (ptr + 2).initialize(to: Person(age: 22, name: "Kate"))
    16. ptr.deinitialize(count: 3)
    17. ptr.deallocate()

     指针之间的转换

    1. var ptr = UnsafeMutableRawPointer.allocate(byteCount: 16, alignment: 1)
    2. ptr.assumingMemoryBound(to: Int.self).pointee = 11
    3. (ptr + 8).assumingMemoryBound(to: Double.self).pointee = 22.0
    4. var ptr2 = unsafeBitCast(ptr, to: UnsafeMutablePointer<Int>.self)
    5. ptr2.pointee = 11
    6. ptr.deallocate()

    1、unsafeBitCast是忽略数据类型的强制转换,不会因为数据类型的变化而改变原来的内存数据

    • 类似于C++中的reinterpret_cast

    局部作用域

    1. class Dog {
    2. var age = 10
    3. func run() {}
    4. }
    5. do {
    6. let dog1 = Dog()
    7. dog1.age = 10
    8. dog1.run()
    9. }
    10. do {
    11. let dog2 = Dog()
    12. dog2.age = 10
    13. dog2.run()
    14. }

  • 相关阅读:
    【微信小程序】image组件的4种缩放模式与9种裁剪模式
    Linux中文乱码问题终极解决方法
    夜莺日志采集mtail
    nsight computer运行失败问题
    无代码开发视图入门教程
    redis常用查询操作
    <C#> C#调用Python脚本方法
    XSS-labs通关游戏
    NiFi中缓存组件的运行机制及增删改缓存数据
    中国移动物联网开放平台OneNET学习笔记(1)——设备接入(MQTT协议)OneNET Studio篇
  • 原文地址:https://blog.csdn.net/run_in_road/article/details/127035043