diff --git a/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift b/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift index 049beae..6d4ee58 100644 --- a/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift +++ b/Example/Tests/ViewModel/GradientLoadingBarViewModelTestCase.swift @@ -17,8 +17,6 @@ class GradientLoadingBarViewModelTestCase: XCTestCase { private var sharedApplicationMock: SharedApplicationMock! private var notificationCenter: NotificationCenter! - private var viewModel: GradientLoadingBarViewModel! - // MARK: - Public methods override func setUp() { @@ -26,14 +24,9 @@ class GradientLoadingBarViewModelTestCase: XCTestCase { sharedApplicationMock = SharedApplicationMock() notificationCenter = NotificationCenter() - - viewModel = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock, - notificationCenter: notificationCenter) } override func tearDown() { - viewModel = nil - notificationCenter = nil sharedApplicationMock = nil @@ -73,16 +66,22 @@ class GradientLoadingBarViewModelTestCase: XCTestCase { keyWindow) } - func testInitializerShouldSetupSuperviewObservableAfterUIWindowDidBecomeKeyNotificationJustOnce() { + func testDeinitShouldResetSuperviewObservableToNil() { // Given - let viewModel = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock, - notificationCenter: notificationCenter) + let keyWindow = UIWindow() + sharedApplicationMock.keyWindow = keyWindow - let expectation = self.expectation(description: "Expected observer for superview to be informed just once.") + // swiftlint:disable:next unnecessary_type + var viewModel: GradientLoadingBarViewModel? = GradientLoadingBarViewModel(sharedApplication: sharedApplicationMock, + notificationCenter: notificationCenter) + + let expectation = self.expectation(description: "Expected observer to be informed to reset superview to nil.") var disposeBag = DisposeBag() - viewModel.superview.subscribe { newSuperview, _ in - guard newSuperview != nil else { + + // swiftlint:disable:next force_unwrapping + viewModel!.superview.subscribe { newSuperview, _ in + guard newSuperview == nil else { // Skip initial call to observer. return } @@ -91,11 +90,7 @@ class GradientLoadingBarViewModelTestCase: XCTestCase { }.disposed(by: &disposeBag) // When - for _ in 1 ... 3 { - sharedApplicationMock.keyWindow = UIWindow() - notificationCenter.post(name: UIWindow.didBecomeKeyNotification, - object: nil) - } + viewModel = nil // Then wait(for: [expectation], timeout: 0.1) diff --git a/GradientLoadingBar/Classes/GradientLoadingBarController.swift b/GradientLoadingBar/Classes/GradientLoadingBarController.swift index 05cba00..8348969 100644 --- a/GradientLoadingBar/Classes/GradientLoadingBarController.swift +++ b/GradientLoadingBar/Classes/GradientLoadingBarController.swift @@ -78,31 +78,24 @@ open class GradientLoadingBarController { bindViewModelToView() } - /// By providing a custom deinitializer we make sure to remove the corresponding `gradientView` from its superview. - deinit { - if gradientView.superview != nil { - gradientView.removeFromSuperview() - } - } - // MARK: - Private methods private func bindViewModelToView() { viewModel.superview.subscribeDistinct { [weak self] newSuperview, _ in - self?.addGradientView(to: newSuperview) + self?.updateSuperview(newSuperview) }.disposed(by: &disposeBag) } - private func addGradientView(to superview: UIView?) { - guard let superview = superview else { - // We've received an invalid superview. - return + private func updateSuperview(_ superview: UIView?) { + // If the view’s superview is not nil, the superview releases the view. + gradientView.removeFromSuperview() + + if let superview = superview { + gradientView.translatesAutoresizingMaskIntoConstraints = false + superview.addSubview(gradientView) + + setupConstraints(superview: superview) } - - gradientView.translatesAutoresizingMaskIntoConstraints = false - superview.addSubview(gradientView) - - setupConstraints(superview: superview) } // MARK: - Public methods diff --git a/GradientLoadingBar/Classes/ViewModel/GradientLoadingBarViewModel.swift b/GradientLoadingBar/Classes/ViewModel/GradientLoadingBarViewModel.swift index d443f47..3f7ac8a 100644 --- a/GradientLoadingBar/Classes/ViewModel/GradientLoadingBarViewModel.swift +++ b/GradientLoadingBar/Classes/ViewModel/GradientLoadingBarViewModel.swift @@ -49,14 +49,16 @@ final class GradientLoadingBarViewModel { } } + deinit { + /// By providing a custom deinitializer we make sure to remove the corresponding `gradientView` from its superview. + superviewSubject.value = nil + } + // MARK: - Private methods @objc private func didReceiveUIWindowDidBecomeKeyNotification(_: Notification) { guard let keyWindow = sharedApplication.keyWindow else { return } - // Prevent informing the listener multiple times. - notificationCenter.removeObserver(self) - // Now that we have a valid key window, we can use it as superview. superviewSubject.value = keyWindow }