swift 如何测试viewController的定义

3j86kqsm  于 2022-12-10  发布在  Swift
关注(0)|答案(3)|浏览(116)

我想测试一下我是否删除了视图控制器deinit中的所有键值观察器。
在测试类中,我定义了以下方法来启动视图控制器生命周期

func startLifecycle() {
   _ = viewController.view
  }

在我的测试方法中,我试图通过简单地将nil赋给视图控制器示例来调用deinit

testViewController = nil
XCTAssert for stuff...

但是当我执行测试时,没有调用deinit。我在VC代码中没有看到明显的保留循环,更重要的是,当我在应用中运行代码时,而不是在测试环境中,调用了deinit,所以看起来不像是有什么东西在内存中保留视图控制器。
测试时释放视图控制器的正确方法是什么?

n3ipq98p

n3ipq98p1#

这样试试smth

class ViewController: UIViewController {
    var deinitCalled: (() -> Void)?
    deinit { deinitCalled?() }
}

class ViewControllerTest: XCTestCase {
    func test_deinit() { 
        var instance: ViewController? = ViewController()
        let exp = expectation(description: "Viewcontroller has deinited")
        instance?.deinitCalled = {
            exp.fulfill()
        }

        DispatchQueue.global(qos: .background).async {
            instance = nil
        }

        waitForExpectations(timeout: 2)
    }
}
u59ebvdq

u59ebvdq2#

I had the same problem.
When you examine the memory graph, you will see that an object of type UIStoryboardScene maintains a reference to your UIViewController via an @autorelease property ' sceneViewController '.
If you're unfamiliar with @autorelease, this is a helpful article: https://swiftrocks.com/autoreleasepool-in-swift . It explains that objects created with autorelease are released at the end of the current thread's run loop, but not before.
In Swift, we can use autoreleasepool to release UIStoryboardScene 's reference to the UIViewController.
It might look something like this:

var testViewController: UIViewController?
autoreleasepool {
    testViewController = UIStoryboard(name: "main", bundle: nil).instantiateInitialViewController()
}

Then, when you execute testViewController = nil , the UIViewController will actually deinit.

6ljaweal

6ljaweal3#

万一别人需要这个,我设法这样做。

// Given
    var optionalSubject: UIViewController? = UIViewController()

    // When
    optionalSubject = nil // Call deinit

    // Then
    // TEST DEINIT

相关问题