//
// AccessMomory.swift
// SwiftCode
//
// Created by Alisa on 2022/4/15.
// Copyright © 2022 Alisa. All rights reserved.
//
import Foundation
/*
独占访问权限是Swift4中引入的一大新特性,很多开发者认为这是一种编译器的编译时特性,可以在数组越界时、对遍历中的数组删添元素时产生编译异常.
其实并非如此,独占内存访问权限特性是一种编译时和运行时的安全特性,其和数组也没有任何关系。
当两个变量访问同一块内存时,会产生独占内存访问权限
在Swift4以前,程序对内存的读写访问并没有严格控制,你在读内存时有写内存操作,或者在写内存时有读操作并不会产生什么异常。Swift4中则引入了
独占内存访问权限的特性,如果符合如下3个条件,则程序会产生读写权限冲突:
1> 至少有一个变量在使用写权限
2> 变量访问的是同一个内存地址
3> 持续时间有重叠
** inout 参数读写权限冲突
一般情况下,值类型的传参总会产生复制操作,inout参数则使得函数内可以直接修改外部变量的值。inout参数是最容易产生读写冲突的场景
** 结构体中自修改函数的读写冲突
** 值类型中属性的读写访问权限冲突
在Swift语言中,像结构体、枚举和元组中都有属性的概念,由于其都是值类型,因此在对不同的属性进行访问时都会产生冲突
在开发过程中大部分对于不同属性的访问都不会产生读写冲突,对不同属性的访问需满足下面3个条件,才不会产生读写冲突:
1> 访问的是存储属性,而不是计算属性
2> 访问的是结构体局部变量(函数中的变量), 而不是全局变量
3> 结构体不被闭包捕获,或者只是被非逃逸的闭包捕获
*/
// inout参数产生的读写权限冲突
class ElectricKettle{
var stepSize = 1
func incrementOne(_ number:inout Int){
//这里会触发读写冲突
//报错:Thread 1: Simultaneous accesses to 0x6000017e70b0, but modification requires exclusive access
number += self.stepSize
}
func incrementTwo(number:inout Int, number2:inout Int){
let a = number + number2
print("a value is: \(a)")
}
}
//结构体中自修改函数的读写冲突
struct Player{
var name:String
var health:Int
var energy:Int
let maxHeight = 10
mutating func shareHealth(_ player:inout Player){
health = player.health
}
}
//值类型中属性的读写访问权限冲突
class Demo{
var playerInformation = (health:10, energy:20)
func balance(_ p1:inout Int, _ p2:inout Int){
}
func test(){
/*这里崩溃了,控制台给出的错误信息:
Simultaneous accesses to 0x600003bcb790, but modification requires exclusive access.
Previous access (a modification) started at SwiftCode`Demo.playerInformation.modify + 41 (0x10a1846b9).
*/
self.balance(&playerInformation.health, &playerInformation.energy)
}
func fix(){
//将playerInformation的health、energy元素赋值给不同的两个Int类型的变量
var p1:Int = self.playerInformation.health
var p2:Int = self.playerInformation.energy
self.balance(&p1, &p2)
}
}
class AccessMomory{
// inout参数读写权限冲突
func useInoutReadAndWrite(){
let ek = ElectricKettle()
ek.stepSize = 2 //变量在这里开着写权限
ek.incrementOne(&ek.stepSize) /*在函数increment()中,inout参数从声明开始到函数结束,这个变量始终开启着写权限,此时传入的参数
为&ek.stepSize,在ek.stepSize被赋值为2时开启着读访问,此时满足上面的权限冲突那三条原则,产生了权限冲突*/
/* 这里程序会崩溃,控制台给的Error信息
Simultaneous accesses to 0x6000017e70b0, but modification requires exclusive access.
Previous access (a modification) started at SwiftCode`ElectricKettle.stepSize.modify + 41 (0x104e9bf79).
*/
}
// inout参数同时访问同一个内存地址,产生读写权限冲突
func useInoutAllRead(){
let ek = ElectricKettle()
ek.stepSize = 3
ek.incrementTwo(number: &ek.stepSize, number2: &ek.stepSize)
/* 控制台给的错误信息:
Simultaneous accesses to 0x600001962db0, but modification requires exclusive access.
Previous access (a modification) started at SwiftCode`ElectricKettle.stepSize.modify + 41 (0x100523c19).
*/
}
//结构体中自修改函数的读写冲突
func useStructureChange(){
var player = Player(name: "jaki", health: 10, energy: 10)
player.health = 20
//报错:Overlapping accesses to 'player', but modification requires exclusive access; consider copying to a local variable
//player.shareHealth(&player)
/*
注意报错原因:
上面的shareHealth函数中使用的health是对self自身的读访问,而inout参数是写访问,所以产生了读写权限冲突
*/
}
//值类型中属性的读写访问权限冲突
func useValueReadAndWrite(){
let demo = Demo()
//demo.test()
//修改一下代码,可以正常运行,如下:
demo.fix()
}
}
Swift 内存安全检查
最新推荐文章于 2023-04-20 14:20:14 发布