为什么这会阻止视图控制器解除分配?

时间:2018-05-15 16:43:57

标签: ios swift memory-leaks

内存泄漏

我花了整整一天的时间追逐来自某个地方的内存泄漏......而我才发现它。

除此之外,我不知道它为什么会破碎。而且我不知道为什么我的改变已经解决了。

因此,我创建了一个最小的破坏性示例,以便在此处尝试清除为什么会发生这种情况。

设置

故事板非常简单。它包含一个UINavigationControllerrootViewController类型为ViewController,而且会推送到AnotherViewController

enter image description here

守则

我有一个协议定义......

protocol MyProtocol {}

AnotherViewController符合它......

class AnotherViewcontroller: UIViewController, MyProtocol {
    deinit {
        print(#function, "Another View Controller")
    }
}

我添加了deinit方法来显示正在发生的事情。

ViewController代码更有趣,但同样简单......

class ViewController: UIViewController, UINavigationControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()

        navigationController?.delegate = self
    }

    func navigationController(_ navigationController: UINavigationController,
                              animationControllerFor operation: UINavigationControllerOperation,
                              from fromVC: UIViewController,
                              to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        switch (fromVC, toVC) {
        case (is MyProtocol, is MyProtocol):
            print(" NOOOOOO!")
            return nil
        default:
            print(" Yippee!")
            return nil
        }
    }
}

ViewController 不符合MyProtocol

它成为navigationController的代表。

并实现返回动画转换控制器的函数。但在这种情况下,我只是return nil因为我不想改变动画。

这里没有什么复杂的事情发生。

运行应用程序......

当我运行应用程序时,它会打开,并在屏幕中央显示Push按钮。我点按Push按钮,转到AnotherViewController。在控制台中我有 Yippee!

当我现在点击后退按钮时,我再次在控制台中获得 Yippee!并弹出回第一个视图控制器。

  

注意:它永远不会显示红苹果。它永远不会进入那种情况。它所做的就是检查fromVCtoVC是否符合MyProtocol

除此之外,AnotherViewController尚未解除分配。 内存泄漏。如果我运行内存图调试器,我可以看到它仍在内存中。

修复...... ????

所以,我找到了两种可能的方法来解决这个问题......做其中任何一个都会解决它。

第一种方式......将class添加到协议中。通过将协议定义更改为protocol MyProtocol: class {},它可以解决问题。它仍会显示青苹果,但现在它将正常释放。

第二种方式......不要问视图控制器是否符合协议。如果我从交换机中删除case (is MyProtocol, is MyProtocol)并保留默认值,那么它现在将正确释放视图控制器并修复内存泄漏。它不会改变行为。它仍然显示青苹果。但现在有效。

"修复"的另一种奇怪方式它

如果我单独留下所有代码并使ViewController也符合MyProtocol,那么AnotherViewController将被正常释放(除非它现在显示红苹果)。

问题

所以...为什么会这样?它对类协议位有意义,因为它现在知道它是一个引用类型......但仍然不确定为什么询问它是否符合导致泄漏?

还有......为什么要问它是否符合非类协议导致它泄漏?

我测试过的其他事情

如果删除switch并仅使用if检查它们是否符合协议if toVC is MyProtocol,那么它仍然可以解除分配。它似乎只是在交换机中。

如果我删除了对协议的检查,而是检查了班级... case (is AnotherViewController, is AnotherViewController):,那么这也不会影响它。它仍然正常解除分配。

如果有人能说清楚这一点,我很想知道这里发生了什么。

由于

0 个答案:

没有答案