88. Исследуем onAppear/onDisappear

88. Исследуем onAppear/onDisappear

Oleg991

Во всех приложениях есть экраны, где нужно при появлении/исчезновении вьюхи выполнить какую-то работу. В этой статье посмотрим на onAppear, onDisappear, которые используются для такой цели в SwiftUI, и сравним их с аналогами из UIKit.

Демонстрация

https://imgur.com/a/DyYbqHB

Пояснение

Будем сравнивать onAppear/onDisappear с такими аналогами из UIKit: viewWillAppear/viewWillDisappear.

Знаю, что там есть еще другие методы, но конкретно в этой статье будут такие.

Подготовка

  1. Сделаем UIViewController
  2. Завернем его в UIViewControllerRepresentable
  3. Сложим все в модификатор

Результат

import SwiftUI
import UIKit

struct BackgroundViewController: UIViewControllerRepresentable {
  let viewWillAppear: () -> Void
  let viewWillDisappear: () -> Void

  func makeUIViewController(context: Context) -> UIViewController {
    let viewController = CustomViewController()
    viewController.viewWillAppearAction = viewWillAppear
    viewController.viewWillDisappearAction = viewWillDisappear
    return viewController
  }

  func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
   
  final class CustomViewController: UIViewController {
    var viewWillAppearAction: (() -> Void)?
    var viewWillDisappearAction: (() -> Void)?

    override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(animated)
      viewWillAppearAction?()
    }
     
    override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      viewWillDisappearAction?()
    }
  }
}

struct UIKitLifeCycleModifier: ViewModifier {
  let viewWillAppear: () -> Void
  let viewWillDisappear: () -> Void
   
  func body(content: Content) -> some View {
    content
      .background(
        BackgroundViewController(
          viewWillAppear: viewWillAppear,
          viewWillDisappear: viewWillDisappear
        )
      )
  }
}

Код для экрана

struct LifeCycleExampleView: View {
  var body: some View {
    NavigationView {
      VStack(spacing: 20) {
        Text("Контент первого экрана")
          .onAppear { print("1 onAppear") }
          .onDisappear { print("1 onDisappear") }
          .modifier(
            UIKitLifeCycleModifier(
              viewWillAppear: { print("1 viewWillAppear") },
              viewWillDisappear: { print("1 viewWillDisappear") }
            )
          )
        NavigationLink(destination: secondDemoView) {
          Text("Открыть второй экран")
        }
      }
    }
    .font(.title)
  }
   
  private var secondDemoView: some View {
    Text("Контент второго экрана")
      .onAppear { print("2 onAppear") }
      .onDisappear { print("2 onDisappear") }
      .modifier(
        UIKitLifeCycleModifier(
          viewWillAppear: { print("2 viewWillAppear") },
          viewWillDisappear: { print("2 viewWillDisappear") }
        )
      )
  }
}

#Preview {
  LifeCycleExampleView()
}

Результаты (часть 1)

Вот такие принты мы видим в консоли:

1 onAppear
1 viewWillAppear
2 onAppear
1 viewWillDisappear
2 viewWillAppear
1 onDisappear
2 viewWillDisappear
1 viewWillAppear
1 onAppear
2 onDisappear

Выводы

  1. onAppear вызывается раньше, чем viewWillAppear
  2. onDisappear вызывается позже, чем viewWillDisappear

Результаты (часть 2)

Вот такие принты мы видим в консоли:

2 viewWillDisappear
1 viewWillAppear
1 onAppear
1 viewWillDisappear
2 viewWillAppear
1 onDisappear

Выводы

Если жест свайпа назад не заканчивается, и верхний экран остается в стеке навигации, то:

  1. Для экрана, который мы начали закрывать, но не закрыли, вызовется только viewWillDisappear, а onDisappear не вызовется вообще
  2. Для родительского экрана, который мы частично увидели при свайпе, вызываются все 4 события, но на этот раз первыми будут события из жизненного цикла UIKit, т.е. viewWillAppear/viewWillDisappear

Заключение

Путем нехитрых экспериментов можно достаточно быстро сравнить поведение SwiftUI-модификаторов для жизненного цикла вьюхи и UIKit-предшественников.

Здорово, если тебе удалось узнать что-то новое, и еще лучше, если это ты сможешь использовать это в своей практике 😉

Код для этой статьи можно посмотреть тут, другие статьи по разработке - тут, а про инвестиции - тут.

Report Page