You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中类/结构体内部计算变量内存地址异常问题求解

问题核心结论

你观察到的计算属性地址不一致的现象和Copy on Write(COW)机制完全无关,本质是你对计算属性的内存特性存在误解。


1 计算属性的本质

计算属性并不占用类/结构体实例的内存空间,它的本质是一对get/set方法:

  • 读取时调用getter,返回内部存储属性的值
  • 写入时调用setter,修改内部存储属性的值

你使用withUnsafePointer(to: &self.testClass.getterSetter)取地址时,Swift会执行以下隐式逻辑:

  1. 调用getterSetter的get方法,拿到返回的String值
  2. 在当前函数栈帧上创建一个临时的String变量存储这个返回值
  3. 把这个临时变量的指针传入闭包供你使用
  4. 如果你在闭包内修改了指针指向的值,离开闭包时会自动调用getterSetter的set方法,把临时变量的新值写回

也就是说你打印的地址根本不是实例内部存储属性的地址,只是当前栈上临时变量的地址,每次调用都会生成新的临时变量,地址自然不一致。


2 你观察到的特殊现象解释
  • 为什么删掉修改getterSetter的代码后两次地址一致:此时两次getter返回的都是初始的"Hello"常量字符串,Swift编译器做了常量优化,两次临时变量指向同一个常量存储空间,所以地址看起来相同,这只是编译优化的结果,不是必然现象。
  • 为什么TestClass实例地址始终不变:你修改的是类实例内部的存储属性,类是引用类型,实例本身的内存地址不会因为内部属性修改而变化。
  • 为什么换成结构体也能复现:和结构体的COW机制没有任何关系,只要是计算属性,取地址时都会生成临时变量,自然地址会变化。

3 正确获取内部存储属性地址的方式

如果你要获取内部存储属性a的真实内存地址,需要直接对存储属性取地址,不能通过计算属性中转:

// 把TestClass的a改成internal或者提供内部取地址的方法
withUnsafePointer(to: &self.testClass.a) {
    print("真实存储属性a的地址:\($0)")
}

这个地址在类实例生命周期内是固定的,如果是结构体的话,只要没有发生COW拷贝,地址也会保持不变。


内容的提问来源于stack exchange,提问作者CaptainSan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 06:36:00