UIViewController变量在释放后仍然存在
我正在尝试编写测试来检查保留周期,但遇到了这种奇怪的行为。当将视图控制器设置为nil
时,A UIViewController
的属性不会取消分配。以此模拟对象为例:UIViewController变量在释放后仍然存在
class BasicViewController: UIViewController {
var someObject = NSObject()
.....
}
它只是一个变量。你会认为当致电basicViewController = nil
会导致someObject
为零,但它不是。
it("releases someObject") {
var controller: MockController? = MockController()
weak var something = controller?.something
expect(controller).toNot(beNil())
controller = nil
expect(controller).to(beNil())
expect(something).to(beNil())
}
it("doesn't release someObject") {
var controller: MockController? = MockController()
weak var something = controller?.something
expect(controller).toNot(beNil())
_ = controller?.view
controller = nil
expect(controller).to(beNil())
expect(something).toNot(beNil())
}
当调用vc.view
这个调用loadView
还有UIViewController
的生命周期功能 - viewDidLoad
,viewDidAppear
和viewWillAppear
。我的问题是为什么?为什么当我引用UIViewController
的view
属性时,即使在将UIViewController
设置为nil
后,所有对象UIViewController
仍然存在。
FWIW,我使用Quick
和Nimble
进行测试,以及Swift 3.1
简短的回答:
添加autoreleasepool
,当对象从池耗尽,这将精确地决定,并且它可以作为你会预料到的。
龙答:
我遇到你描述相同的行为。但问题不是视图控制器的属性。这是视图控制器本身。
在您的示例中,您将controller
设置为nil
,并使用现在是nil
的事实来推断控制器是否已解除分配。但这只是测试对视图控制器的特定引用是否为nil
,但视图控制器本身可能尚未释放。但是您可以使用您的视图控制器本身的weak var
测试。考虑这个视图控制器:
class BasicViewController: UIViewController {
// this is intentionally blank
}
,其视图控制器,体现的是您所描述的行为,其中装载的观点之后XCTAssertNil
测试失败,我可以写测试:
class MyApp2Tests: XCTestCase {
func testWithoutView() {
var controller: BasicViewController? = BasicViewController()
weak var weakController = controller
XCTAssertNotNil(weakController)
controller = nil
XCTAssertNil(weakController) // this succeeds
}
func testWithView() {
var controller: BasicViewController? = BasicViewController()
weak var weakController = controller
XCTAssertNotNil(weakController)
controller?.loadViewIfNeeded()
controller = nil
XCTAssertNil(weakController) // this fails
}
}
但是,当我添加了一个autoreleasepool
明确地控制池何时耗尽,它如预期般工作:
func testWithViewAndAutoreleasePool() {
weak var weakController: BasicViewController?
autoreleasepool {
var controller: BasicViewController? = BasicViewController()
weakController = controller
XCTAssertNotNil(weakController)
controller?.loadViewIfNeeded()
controller = nil
}
XCTAssertNil(weakController) // this succeeds
}
顺便说一句,如果您正在寻找另外l确认视图控制器本身的释放时机,在deinit
(以及您设置的controller = nil
)中添加一条print
语句,您会看到deinit
的时间在做任何加载视图。
我无法解释这种行为。为什么要用view
做一些事情会影响视图控制器的生命周期?顺便说一句,我也使用视图控制器的属性执行上述测试,就像你的问题一样,我看到完全相同的行为(但恕我直言,这并不令人惊讶,因为它只是因为视图控制器本身没有被释放)。
至少我们可以用autoreleasepool
明确控制自动释放池的生命周期时序。
但是,如果您查看两个测试,两者之间的唯一区别是我调用_ = vc.view,这导致我必须使用toNot()来使测试通过。这是不希望的。我创建了这个例子来展示最简单的对象如何导致这种持久性的发生。没有强大的引用周期发生,有些东西只是一个NSObject。它让我相信,当与视图交互时,控制器的属性会持续存在,但最终会在一段时间后解除分配。 – jsetting32