Swift XCTest:验证弱变量的正确释放
最近,我尝试使用单元测试验证我编写的对象是否正确释放。然而,我发现无论我尝试了什么,在测试完成之前对象都不会释放。因此,我将测试简化为一个简单的示例(见下文),该示例试图证明使用弱变量进行对象释放的基础 在我看来,强引用应该在测试方法退出后停止保留对象,而弱引用在下一个运行循环中引用时应该为nil。然而,弱参考永远不会为零,并且两个测试都失败。我是不是误解了什么?下面是完整的单元测试Swift XCTest:验证弱变量的正确释放,swift,xctest,weak,capture-list,Swift,Xctest,Weak,Capture List,最近,我尝试使用单元测试验证我编写的对象是否正确释放。然而,我发现无论我尝试了什么,在测试完成之前对象都不会释放。因此,我将测试简化为一个简单的示例(见下文),该示例试图证明使用弱变量进行对象释放的基础 在我看来,强引用应该在测试方法退出后停止保留对象,而弱引用在下一个运行循环中引用时应该为nil。然而,弱参考永远不会为零,并且两个测试都失败。我是不是误解了什么?下面是完整的单元测试 class Mock { //class type, should behave with reference
class Mock { //class type, should behave with reference semantics
init() { }
}
class DeallocationTests: XCTestCase {
func testWeakVarDeallocation() {
let strongMock = Mock()
weak var weakMock: Mock? = strongMock
let expt = expectation(description: "deallocated")
DispatchQueue.main.async {
XCTAssertNil(weakMock) //This assertion fails
expt.fulfill()
}
waitForExpectations(timeout: 1.0, handler: nil)
}
func testCaptureListDeallocation() {
let strongMock = Mock()
let expt = expectation(description: "deallocated")
DispatchQueue.main.async { [weak weakMock = strongMock] in
XCTAssertNil(weakMock) //This assertion also fails
expt.fulfill()
}
waitForExpectations(timeout: 1.0, handler: nil)
}
}
我认为XCTest可能以某种方式推迟了释放,但即使将测试方法体包装在
autoreleasepool
中也不会导致对象释放。问题在于您的TestWeakvardAllocation()调用dispatchAsync
块时,
函数尚未退出,因此仍保留对strongMock
的强引用
像这样尝试(允许退出testWeakVarDeallocation()
),您将看到weakMock
按预期变成nil
:
class weakTestTests: XCTestCase {
var strongMock: Mock? = Mock()
func testWeakVarDeallocation() {
weak var weakMock = strongMock
print("weakMock is \(weakMock)")
let expt = self.expectation(description: "deallocated")
strongMock = nil
print("weakMock is now \(weakMock)")
DispatchQueue.main.async {
XCTAssertNil(weakMock) // This assertion fails
print("fulfilling expectation")
expt.fulfill()
}
print("waiting for expectation")
self.waitForExpectations(timeout: 1.0, handler: nil)
print("expectation fulfilled")
}
}
weakMock
需要是可选的,例如弱变量weakMock:Mock?=strongMock
。如果不能将其设置为nil
,则无法释放。@parweakMock
是自动可选的,由编译器强制执行。如果检查weakMock
的类型,它已经是Mock?
,没有显式的类型注释。如果显式地将其设置为可选,它会变成nil吗?@par,不幸的是,它不会。为了完整起见,我将向示例中添加类型注释。谢谢,但我认为这是一个同步问题。由于您正在调用waitforexpections()
,因此调用异步块时,testWeakVarDeallocation()
函数尚未退出。因此,对strongMock
的引用仍然保留,因此weakMock
无法转到nil
。关于对象为什么不解除分配,您是对的,但您的解决方案无法解决问题。测试在第一个异步块运行之前完成并通过,因为没有等待的期望。完全是第二十二条军规。你说得对,XTest函数不会等待。我已经更新了答案,现在它做了正确的事情。是的,这是可行的,我用autoreleasepool解决了下面的问题,但是你的解决方案基本上是一样的。谢谢你的帮助!事实上是不同的。Swift对象不会像您熟悉的(旧式)Objective-C那样被保留和自动删除。由于范围的原因,只有引用计数。