swift - 协议(protocol)对保留计数有影响吗?

标签 swift memory-management memory-leaks protocols

我有一个非常简单的代码。我有意用委托(delegate)创建一个内存周期。尝试观察和学习如何使用 Xcode 的内存图。

我不明白的是为什么在连接部分,Xcode 说有 3 个连接。应该只有 2 个。

enter image description here

如果我使用 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_retainswift_release 上设置符号断点,以便查看强大的保留/释放 Swift ARC 流量(同时打印出存储在 >%rdi 寄存器,它似乎是用于在 x86 上传递参数的寄存器):

enter image description here

然后在调用 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/

相关文章:

ios - 不能使用 NSMutableDictionary 键作为数组中的索引吗?

Swift 4 ImageScrollView 调整 UITableView 中可见单元格的大小

c# - 在 C# 中使用大量 COM 对象的内存使用过多

hadoop - Mesos是否覆盖Hadoop内存设置?

C++:内存泄漏;类 vector 类

ios - 当我在搜索栏上单击取消时,如何重新加载 tableview 中的所有数据?(IOS/Swift)

ios - 检测音量按钮即使在音量最大时按下

iOS 核心数据怎么会泄露?

multithreading - 使用 OpenMP 时发生内存泄漏

memory-leaks - 如何解码 node.js 中内存数据的含义并调试内存泄漏?