2016-12-23 11 views
1

Недавно я пытался проверить, что объект, который я написал, правильно освобождает, используя модульный тест. Однако я обнаружил, что независимо от того, что я пробовал, объект не будет освобожден до завершения теста. Поэтому я уменьшил тест до тривиального примера (см. Ниже), который пытается доказать основы снятия объекта с использованием слабых переменных.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 не вызывает объект для освобождения.

+0

'weakMock' должен быть необязательным, например, 'слабый var weakMock: Mock? = strongMock'. Если он не может быть установлен в 'nil', он не может быть выпущен. – par

+0

@par 'weakMock' автоматически опционально, который выполняется компилятором. Если вы проверите тип 'weakMock', это уже' Mock? 'Без явной аннотации типа. –

+0

И если вы сделаете это явно необязательным, станет ли оно нулевым? – par

ответ

3

Проблема заключается в том, что функция 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") 
    } 
} 
+0

Вы правы в том, почему объект не освобождается, но ваше решение не устраняет проблему. Тест завершается и проходит до того, как будет запущен первый асинхронный блок, потому что ожидания не ожидаются. Довольно поймать-22. –

+0

Вы правы, функция XCTest не ждет. Я обновил ответ, и теперь он делает правильные вещи. – par

+0

Да, это работает, я понял проблему ниже, используя autoreleasepool, но ваше решение по сути то же самое. Спасибо за помощь! –

 Смежные вопросы

  • Нет связанных вопросов^_^