Swift 初阶 —— inout 参数 & 数据独占问题

一、前言

我们都知道, 在 swift 里 inout 参数是用来修改实参的. 但其实 inout 参数的使用是要遵循"数据独占性"的, 要不然编译器会报错或警告.

inout 参数实际上只把对象的地址传了进来.

二、数据独占性

1、什么是数据独占

简单来说, "数据独占" 就是在单线程环境下, 当你往一块连续的内存写东西的同时, 不能读这块内存且不能同时往这块内存写其他东西.

2、为什么只有值类型才会有数据独占, 引用类型没有

这就涉及到 Swift 的设计哲学了. 因为一个引用类型的对象是一个指针而已, 且这个指针指向的实例是在堆上创建的, 所以这个堆上的实例是允许同时被多个指针指着的, 所以这个堆上的实例天生被设计出来就是为了共享的, 因此就引用类型没有数据独占这一说了.

但一个值类型的对象就是一块在栈上的连续内存, 不是指针. 所以值类型对象天生的设计就是不被共享的, 所以 Swift 才会在传 inout 参数时对值类型的对象实施数据独占.

3、访问重叠

3.1. 什么是访问重叠

访问重叠就是给多个 inout 参数传同一块连续内存. 这样做会导致 Swift 认为你在这个函数里同时对这块连续内存多次写入, 或边写边读, 于是 Swift 就认为你在破坏数据独占.

3.2. 访问重叠经典例子

3.2.1. 向多个 inout 参数传同一块连续内存

a. 同一个变量

b. 同一个数组(因为数组是内存连续的)

c. 同一个 struct 对象
图1 图 1 报错原因:

因为 state 传的是整块 appState 的内存, 而 max 传的是 appState 里的 limit 那块内存, 这两块内存是重叠了的, 所以 Swift 会怀疑你会对重叠的那部份内存边读边写, 于是就会报访问重叠 (overlapping accesses) 的错误.
图2 图 2 没报错原因:

这其实是 Swift6 的优化. appState 的 counter 和 appState 的 limit 这两块内存是不重叠的, 因此把这两块内存传到 value 和 max, 不会引起访问重叠的错误. 但这只是对 struct 的优化, 并不是对所有值类型对象的优化.

3.2.2. mutating 方法里使用逃逸闭包, 并在逃逸闭包里向 inout 参数写入

图 3 图 3 报错原因:

  1. inout 参数实际上只把对象的地址传了进来.
  2. mutating 方法实际会把 self 以 inout 的形式传进来, 因此 mutating 方法会对 self 要有数据独占性. 而如果如图 3 所示在逃逸闭包里修改 self, Swift 会认为你会在调用其他 mutating 方法时执行这个闭包, 那么对其他 mutating 方法而言就做不到 "数据独占" 了 (因为其他 mutating 函数里可能会出现同时向同一块内存写入的情况).
    图 4 图 4 为正确解决方案:

当我们把 self 声明在捕获列表里后, swift 实际上会把 self 拷贝出一个只读的副本, 然后再让闭包捕获这个不可变的副本. 所以闭包读到的 self 和 mutating 捕获到的 self 就不是同一块内存了, 就保证了 mutating 函数的 self 的数据独占.

三、总结

所以综上所述, swift 对 inout 参数的规定就是: inout 参数只能在当前函数的作用域内访问, 同时不能访问重叠. 除此之外, mutating 函数、setter、didSet & willSet 实际上都会把 self 以 inout 的方式传进来, 因此不能再这些函数里建一个逃逸闭包, 然后再在这个逃逸闭包里向 self 写值.

相关推荐
呆呆虫1213 分钟前
用 orjson 加速 SerpBase 响应解析:基准对比与注意事项
开发语言·php
心疼你的一切40 分钟前
Python自动发邮件实战定时发报表
大数据·开发语言·python
Wang's Blog2 小时前
Java 项目实战:交友项目 - 用户体系集成总结
java·开发语言·交友
Brilliantwxx2 小时前
【STM32】 内部 Flash 详解:寄存器逐位拆解 + 工作流程顺序全讲 + EEPROM再实现
stm32·单片机·嵌入式硬件·1024程序员节
中科三方2 小时前
IPv6检测常见问题:AAAA记录检测不通过是什么原因?
开发语言·php
一只鹿鹿鹿3 小时前
智算算力、AI-芯片与产品解析(PPT文件)
大数据·运维·网络·人工智能·物联网·1024程序员节
沫璃染墨3 小时前
从零入门计算机网络系列(十一):HTTP协议进阶——从重定向原理到GET/POST与Fiddler抓包
linux·服务器·开发语言·网络·c++·tcp/ip·html
xwz小王子3 小时前
Science Advances 让机器人触觉在重压下继续分辨微小变化
机器人·1024程序员节
小小AK3 小时前
聚水潭售后单到金蝶退货单同步实战:从增量拉取到目标单据落库的全流程拆解
1024程序员节