Swift 内存安全检查

//
//  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()
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值