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")
    }
}
Другие вопросы по тегам