协议对保留计数有影响吗? [英] Do protocols have an effect on the retain count?

查看:66
本文介绍了协议对保留计数有影响吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的代码.我有目的创建了一个与委托相关的记忆周期.尝试观察和学习如何使用Xcode的内存图.

I have a very simple code. I’m PURPOSELY creating a memory cycle with a delegate. Trying to observe and learn how to use Xcode's Memory Graph.

我不明白的是为什么在连接部分中,Xcode表示存在 3 个连接.应该只有2.

What I don’t get is why in the connections sections, Xcode says there are 3 connections. There should only be 2.

如果我创建一个带有闭包的内存循环,那么它将显示 2 个连接.

If I create a memory cycle with with closures, then it will show 2 connections.

我与委托一起泄漏的代码:

My code for leaking with 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!!!")
    }
}

我将该视图推送到navigationController中,然后返回.

I push that view into a navigationController then go back.

2个委托对象的内存地址略有不同,只是一个+16

The 2 delegate objects have a slightly different memory addresses, it differs just by a +16

似乎与委托对象是协议有关.因为当我删除该协议时,它缩减为 2 :

It seems that it has something to do with delegate object being a protocol. Because when I removed the protocol, then it reduced down to 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引起的困惑.协议值不应导致超出正常强引用的任何额外保留,因为内存管理操作通过存在容器中存储的类型元数据转发到基础值.

I'm pretty sure that this is just Xcode getting confused. A protocol value shouldn't cause any extra retains over a normal strong reference, as memory management operations are forwarded to the underlying value through the type metadata stored within the existential container.

这是一个最小的示例,可以在Xcode的内存图调试器中重现相同的结果:

Here's a minimal example that reproduces the same result in Xcode's memory graph debugger:

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 ^")

如果在打印语句之间插入一个断点并查看内存图,则会看到3个连接.有趣的是,如果在分配d.p之后分配c.d,则会看到2个连接的正确结果.

If you insert a breakpoint between the print statements and look at the memory graph, you'll see 3 connections. Interestingly enough, if you assign c.d after you assign d.p, you'll see the correct result of 2 connections instead.

但是,如果我们在swift_retainswift_release上设置符号断点以查看强大的保留/释放Swift ARC流量(同时打印出存储在%rdi寄存器中的值,该值似乎是所使用的寄存器)在x86上传递参数):

However if we set symbolic breakpoints on swift_retain and swift_release in order to see the strong retain/release Swift ARC traffic (while printing out the value stored in the %rdi register, which appears to be the register used to pass the argument on x86):

,然后在调用foo()之后立即插入一个断点,我们可以看到,在这两种情况下,实例各自保留+2并释放-2(请记住,它们以+1保留的形式进入世界,因此保持已分配):

and then insert a breakpoint immediately after the call to foo(), we can see that in both cases the instances each get +2 retained and -2 released (bearing in mind they enter the world as +1 retained, thus keeping them allocated):

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.

So it looks like Xcode is at fault here, not Swift.

这篇关于协议对保留计数有影响吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆