我有一个非常简单的代码。我有意用委托(delegate)创建一个内存周期。尝试观察和学习如何使用 Xcode 的内存图。
我不明白的是为什么在连接部分,Xcode 说有 3 个连接。应该只有 2 个。
如果我使用 with 闭包创建一个内存周期,那么它将显示 2 个连接。
我的委托(delegate)泄漏代码:
protocol SomeDelegate {
func didFinishSomething()
}
class Something {
var delegate: SomeDelegate?
}
class ViewController: UIViewController, SomeDelegate {
var x = Something()
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
x.delegate = self
}
func didFinishSomething() {
print("something was finished")
}
deinit {
print("dellocated!!!")
}
}
我将该 View 推送到导航 Controller 中,然后返回。
这 2 个委托(delegate)对象的内存地址略有不同,仅相差 +16
这似乎与委托(delegate)对象作为协议(protocol)有关。因为当我删除协议(protocol)时,它减少到 2:
class Something2 {
var delegate: ViewController?
}
class ViewController: UIViewController {
var x = Something2()
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
x.delegate = self
}
deinit {
print("dellocated!!!")
}
}
最佳答案
我很确定这只是 Xcode 感到困惑。协议(protocol)值不应导致对普通强引用的任何额外保留,因为内存管理操作通过存储在存在容器中的类型元数据转发到底层值。
下面是一个在 Xcode 内存图调试器中重现相同结果的最小示例:
protocol P {}
class C : P {
var d: D?
}
class D {
var p: P?
}
func foo() {
let c = C()
let d = D()
c.d = d
d.p = c
}
foo()
print("insert breakpoint V")
print("insert breakpoint ^")
如果您在 print 语句之间插入断点并查看内存图表,您将看到 3 个连接。有趣的是,如果您在分配 d.p
之后分配 c.d
,您将看到 2 个连接的正确结果。
但是,如果我们在 swift_retain
和 swift_release
上设置符号断点,以便查看强大的保留/释放 Swift ARC 流量(同时打印出存储在 >%rdi
寄存器,它似乎是用于在 x86 上传递参数的寄存器):
然后在调用 foo()
之后立即插入一个断点,我们可以看到,在这两种情况下,每个实例都获得 +2 保留和 -2 释放(记住它们进入了世界)保留+1,从而保持它们的分配):
swift_retain 1
rdi = 0x000000010070fcd0
swift_retain 2
rdi = 0x000000010070fcd0
swift_release 1
rdi = 0x0000000000000000
swift_release 2
rdi = 0x000000010070fcd0
swift_retain 3
rdi = 0x00000001007084e0
swift_retain 4
rdi = 0x00000001007084e0
swift_release 3
rdi = 0x00000001007084e0
swift_release 4
rdi = 0x000000010070fcd0
swift_release 5
rdi = 0x00000001007084e0
所以看来这里的问题是 Xcode,而不是 Swift。
关于swift - 协议(protocol)对保留计数有影响吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56227192/