25、【Swift】内存安全

2021-01-05  本文已影响0人  Sunday_David

理解内存访问冲突

// 向 one 所在的内存区域发起一次写操作
var one = 1

// 向 one 所在的内存区域发起一次读操作
print("We're number \(one)!")
../_images/memory_shopping_2x.png

这里访问冲突的讨论是在单线程的情境下讨论的,并没有使用并发或者多线程。

在单线程遇到内存访问冲突,Swift 会保证你在要么编译时要么运行时得到错误。

对于多线程的代码,可以使用 Thread Sanitizer 去帮助检测多线程的冲突

内存访问性质

func oneMore(than number: Int) -> Int {
    return number + 1
}

var myNumber = 1
myNumber = oneMore(than: myNumber)
print(myNumber)
// 打印“2”

In-Out 参数的访问冲突

var stepSize = 1// 全局变量

func increment(_ number: inout Int) {
    number += stepSize //  stepSize 的读访问与 number 的写访问重叠了
}

increment(&stepSize)
// 错误:stepSize 访问冲突
image
// Make an explicit copy.
var copyOfStepSize = stepSize
increment(&copyOfStepSize)
 
// Update the original.
stepSize = copyOfStepSize
// stepSize is now 2
// stepSize is now 2
func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // 正常, 访问的是不同的内存位置
balance(&playerOneScore, &playerOneScore)// 同时访问同一个的存储地址。
// 错误:playerOneScore 访问冲突

操作符也是函数,也会对 in-out 参数进行长期访问

balance(_:_:) 是一个名为 <^> 的操作符函数,那么 playerOneScore <^> playerOneScore 也会造成像 balance(&playerOneScore, &playerOneScore) 一样的冲突

方法里 self 的访问冲突

struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}

extension Player {
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health)
    }
}

var oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "Maria", health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // 正常
img
oscar.shareHealth(with: &oscar)
// 错误:oscar 访问冲突
image
oscar.shareHealth(with: &oscar)
// 错误:oscar 访问冲突
image

属性的访问冲突

var playerInformation = (health: 10, energy: 20)
balance(&playerInformation.health, &playerInformation.energy)
// 错误:playerInformation 的属性访问冲突
var holly = Player(name: "Holly", health: 10, energy: 10)
balance(&holly.health, &holly.energy)  // 错误
func someFunction() {
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    balance(&oscar.health, &oscar.energy)  // 正常
}
// 两个存储属性任何情况下都不会相互影响(全局变量,传指针,局部变量传值)
上一篇 下一篇

猜你喜欢

热点阅读