我想测试是否删除了视图控制器的deinit
中的所有键值观察器。
在测试类中,我定义了以下方法来启动视图控制器生命周期
func startLifecycle() {
_ = viewController.view
}
在我的测试方法中,我试图通过简单地将nil分配给我的视图控制器实例来调用deinit
testViewController = nil
XCTAssert for stuff...
但是当我执行测试时没有调用deinit
。我发现我的VC代码中没有明显的保留周期,当我在我的应用程序中运行代码而不是测试环境时会更多,deinit
被调用所以它看起来并不像喜欢把控制器留在记忆中的东西。
测试时释放视图控制器的正确方法是什么?
答案 0 :(得分:2)
我做了一个小测试。当我使用标准的单视图应用程序并将以下内容添加到ViewController时:
var value: Int? = 1
deinit {
value = nil
}
并运行以下测试:
func testExample() {
var viewController: ViewController? = ViewController()
XCTAssertEqual(viewController?.value, 1)
viewController = nil
}
deinit由测试执行(使用deinit中的断点检查)。
答案 1 :(得分:1)
尝试这样
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)
}
}
答案 2 :(得分:1)
我有同样的问题。
检查内存图时,您会看到类型UIStoryboardScene
的对象通过UIViewController
属性'@autorelease
'维护对sceneViewController
的引用。 / p>
如果您不熟悉@autorelease,这是一篇很有帮助的文章:https://swiftrocks.com/autoreleasepool-in-2019-swift.html。它解释了使用自动释放创建的对象将在当前线程的运行循环结束时释放,而不是在之前释放。
在Swift中,我们可以使用autoreleasepool
释放UIStoryboardScene
对UIViewController的引用。
它可能看起来像这样:
var testViewController: UIViewController?
autoreleasepool {
testViewController = UIStoryboard(name: "main", bundle: nil).instantiateInitialViewController()
}
然后,当您执行testViewController = nil
时,UIViewController实际上将取消初始化。
答案 3 :(得分:0)
万一有人需要,我设法这样做了。
// Given
var optionalSubject: UIViewController? = UIViewController()
// When
optionalSubject = nil // Call deinit
// Then
// TEST DEINIT