Swift XCTest: проверка правильного освобождения слабых переменных
Недавно я пытался проверить правильность освобождения объекта, который я написал, с помощью модульного теста. Однако я обнаружил, что независимо от того, что я пробовал, объект не будет освобожден до завершения теста. Поэтому я сократил тест до тривиального примера (см. Ниже), который пытается доказать основы освобождения объекта с помощью слабых переменных.
На мой взгляд, сильная ссылка должна прекратить удерживать объект после выхода из метода тестирования, а слабая ссылка должна быть нулевой при ссылке на следующий цикл выполнения. Однако слабая ссылка никогда не равна нулю, и оба теста не пройдены. Я что-то здесь неправильно понимаю? Ниже приведены модульные тесты в полном объеме.
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
не вызывает освобождение объекта.
1 ответ
Проблема в том, что ваш testWeakVarDeallocation()
функция не вышла, когда 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")
}
}