Swift中类/结构体内部计算变量内存地址异常问题求解
问题核心结论
你观察到的计算属性地址不一致的现象和Copy on Write(COW)机制完全无关,本质是你对计算属性的内存特性存在误解。
1 计算属性的本质
计算属性并不占用类/结构体实例的内存空间,它的本质是一对get/set方法:
- 读取时调用getter,返回内部存储属性的值
- 写入时调用setter,修改内部存储属性的值
你使用withUnsafePointer(to: &self.testClass.getterSetter)取地址时,Swift会执行以下隐式逻辑:
- 调用
getterSetter的get方法,拿到返回的String值 - 在当前函数栈帧上创建一个临时的
String变量存储这个返回值 - 把这个临时变量的指针传入闭包供你使用
- 如果你在闭包内修改了指针指向的值,离开闭包时会自动调用
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
相关产品推荐
相关产品推荐

