繁体   English   中英

关闭视图控制器时,在应用程序中调用了deinit,但未在单元测试中调用过deinit

[英]deinit called in app but not in unit test when dismissing view controller

我试图对视图控制器的内存进行单元测试,以查看它们在被关闭时是否正确地初始化。

class SettingsViewControllerTests: XCTestCase {

    var controller: SettingsViewController!

    override func setUp() {
        super.setUp()

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        controller = storyboard.instantiateViewController(withIdentifier: "SettingsViewController")
            as? SettingsViewController

        //load view hierarchy
        _ = controller.view
    }

    func testLogout() {
        let sideMenu = MockSideMenuViewController()
        var navController: UINavigationController? = UINavigationController(rootViewController: sideMenu)
        sideMenu.show(navController!, sender: nil)
        navController?.pushViewController(controller, animated: true)
        expect(navController).toNot(beNil())
        controller.dismiss(animated: false, completion: nil)

        expect(navController).toEventually(beNil(), timeout: 3) // fails
        expect(self.controller).toEventually(beNil(), timeout: 3) // fails
    }

在应用程序中,我使用segue展示了我的导航控制器+ SettingsViewController。 它有一个自身调用dismiss的方法,但是当我检查控制器实例时,它们仍然存在。 在我的视图控制器中,我设置了一条打印语句,以检查是否正在调用deinit,当我执行应用程序中的步骤时,确实会调用它(两个控制器最终都变为nil )。 但是,单元测试不能做到这一点。 我想念什么?

controller是一个强烈持有的属性,因此您的测试将保留它。 现在,它仅在随后对setUp()调用中被取消初始化。 如果要专门测试controller.deinit ,请在测试中执行controller = nil

您可能会执行以下操作:

var controller: SettingsViewController!  // <--- this is a strong ref

func testLogout() {
        let sideMenu = MockSideMenuViewController()

        // navController is a strong ref, held until the end of the scope; don't expect it to be nil
        var navController: UINavigationController? = UINavigationController(rootViewController: sideMenu)
        sideMenu.show(navController!, sender: nil)
        navController?.pushViewController(controller, animated: true)

        // hold a weak ref to your controller and then nil out its reference
        weak var weakController = controller

        // remove the strong reference
        controller = nil

        // popping will release the last reference 
        navController?.popViewController(animated: false)

        expect(weakController).to(beNil(),) // succeeds
    }

一些注意事项:

  • navController是作用域级别的变量。 直到函数结束才为零,因此没有理由进行测试或期望。 创建它之后,它肯定也不会为零。

  • UIViewController.dismiss(...)用于消除模态。 您的控制器是导航堆栈的一部分。 开除将不会达到您的期望。

感觉就像您在期待var navController: UINavigationController? 变得虚弱,但事实并非如此。 weak var和属性应该是Optional ,但是可选并不意味着weak 请参阅弱引用

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM