Swift知识点24 - 内存安全

同时读写一个存储地址,会引发访问冲突。

重叠访问主要出现在:

  1. 使用in-out参数的函数和方法
  2. 结构体的mutating方法里

in-out参数的访问冲突

  1. 变量传入inout参数的方法之后,调用方法的同时又访问了传入的变量
var stepSize = 1
    
    func increment(_ number: inout Int) {
        number += stepSize
    }
    
    func test() {
        // 复制一份
        // 否则报错:Simultaneous accesses to 0x7fda39420ca0, but modification requires exclusive access.
        var copyStepSize = stepSize
        increment(©StepSize)
    }
  1. 同一个变量传入了含有多个inout参数的方法里,造成同时访问的情况
func balance(_ x: inout Int, _ y: inout Int) {
        let sum = x + y
        x = sum / 2
        y = sum - x
    }
    
    func test() {
        var playerOneScore = 42
        var playerTwoScore = 30
        balance(&playerOneScore, &playerTwoScore)  // 正常
        // copy之后
        var copyPlayerOneScore = playerOneScore
        var copyPlayerTwoScore = playerOneScore
        balance(©PlayerOneScore, ©PlayerTwoScore)
        print(copyPlayerOneScore)
        // 错误:playerOneScore 访问冲突
    }
  1. 结构体的mutating方法
    对self的写操作会从mutating方法的开始到结束。
    mutating 方法在调用期间需要对 self 发起写访问,而同时 in-out 参数也需要写访问。

属性的访问冲突

任何情况下,对于元组元素的写访问都需要对整个元组发起写访问。这意味着对于 playerInfomation 发起的两个写访问重叠了,造成冲突。
使用inout参数同时传入元组的2个元素的话,就会同时访问元组引起冲突。

限制结构体属性的重叠访问对于内存安全并不总是必要的。内存安全是必要的,但访问独占权的要求比内存安全还要更严格 —— 意味着即使有些代码违反了访问独占权的原则,也是内存安全的。如果编译器可以保证这种非专属的访问是安全的,那 Swift 就会允许这种内存安全的行为。特别是当你遵循下面的原则时,它可以保证结构体属性的重叠访问是安全的:

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

如果编译器无法保证访问的安全性,它就不会允许访问。

你可能感兴趣的:(Swift知识点24 - 内存安全)