swift - 测试 UINavigationController 释放失败?
问题描述
我有以下单元测试:
func testReferences() throws {
var strongVC: UIViewController? = UIViewController()
var strongNC: UINavigationController? = UINavigationController(rootViewController: strongVC!)
weak var weakVC = strongVC
weak var weakNC = strongNC
strongVC = nil
XCTAssertNotNil(weakVC)
XCTAssertNotNil(weakNC)
strongNC = nil
XCTAssertNil(weakVC) // fails
XCTAssertNil(weakNC) // fails
}
最后两个断言失败了。有什么方法可以可靠地测试 UIViewController 和 UINavigationController 的释放吗?
解决方案
我记得,文档说弱持有的对象“可能随时释放”。操作部分是“可能是”。
我猜你的视图控制器和导航控制器是自动释放的。这是一个可以追溯到手动引用计数时代的术语,但在幕后仍然相关。创建对象时保留计数为 1,然后将其添加到“自动释放池”中。然后,下次你的应用程序的当前函数返回并访问事件循环时,“自动释放池已耗尽”,这意味着自动释放池中的每个条目都会收到一条释放消息,将其保留计数减 1。保留计数下降到零,对象被释放。
(ARC 实际上在幕后使用引用计数,因此保留计数和自动释放池仍然相关。只是使用 ARC,编译器会为您维护它们。您的强引用和弱引用变成了对低级系统保留、释放和自动释放功能。)
我不确定它是否可以在测试环境中工作,但您也许可以使用这样的代码:
func testReferences() throws {
var strongVC: UIViewController? = UIViewController()
var strongNC: UINavigationController? = UINavigationController(rootViewController: strongVC!)
weak var weakVC = strongVC
weak var weakNC = strongNC
strongVC = nil
XCTAssertNotNil(weakVC)
XCTAssertNotNil(weakNC)
strongNC = nil
DispatchQueue.main.async {
XCTAssertNil(weakVC) // fails
XCTAssertNil(weakNC) // fails
}
}
}
该代码将导致调用XCTAssertNil()
被推迟到下一次通过事件循环。
该代码的问题在于,在DispatchQueue.main.async()
执行调用时,测试可能已经结束。
编辑:
正如 Cristik 在他们的评论中指出的那样,更好的方法是使用 autoreleasepool 命令:
func testReferences() throws {
//Define the vars we want to test outside of the auto-release pool statement.
weak var weakVC: UIViewController
weak var weakNC: UINavigationController
autoreleasepool {
var strongVC: UIViewController? = UIViewController()
var strongNC: UINavigationController? = UINavigationController(rootViewController: strongVC!)
weakVC = strongVC
weakNC = strongNC
strongVC = nil
XCTAssertNotNil(weakVC)
XCTAssertNotNil(weakNC)
strongNC = nil
}
//Test for nil outside of the autorelasepool statement,
//after the auto-release pool is drained.
XCTAssertNil(weakVC) // fails
XCTAssertNil(weakNC) // fails
}
推荐阅读
- javascript - 按升序排序
- python - 从给定的开始/结束日期列表创建“PeriodIndex”
- python - Networkx Graph获取每个节点的序列号
- visual-studio - Visual Studio 2019 编辑并继续无法正常工作
- google-cloud-platform - GCP 中 Google 托管服务帐户和默认服务帐户之间的区别
- python - 如何按日期时间有效地组合两个大型 Pandas 数据帧
- apache-kafka - 杀死经纪人后,Kafka 流中的“由于致命错误而中止生产者批次”
- odbc - C 中的 Firebird 4.0 候选版本 1 无法打开嵌入式数据库
- sql-server - 如何从 SQL 中的 XML 查询中获取选择列、条件列和 where 子句?
- sql - 为什么无法在 sql plus 中选择/查看表?[固定的]