September 27, 2024

86. Пример работы с NotificationCenter в SwiftUI

NotificationCenter — позволяет отправлять события и подписываться на них в нужных местах приложения, чтобы выполнять какие-то действия. Покажу как это работает в SwiftUI.

Алгоритм действий

  1. Сверстаем переиспользуемую вьюху для двух примеров работы с NotificationCenter
  2. Нужно подписаться на событие NotificationCenter. В нашем примере сделаем 2 варианта реализации: с использованием onReceive прямо во вьюхе и с использованием Combine во вьюмодели
  3. Нужно отправить уведомление через NotificationCenter. В моих примерах будем отправлять текст в поле object.

Подготовка

Чтобы не писать каждый раз название уведомления, сделаем для него константу:

enum NotificationCenterExample {
  static let notificationName = Notification.Name("демо.уведомление")
}

Верстаем вьюху для примеров

struct DemoView: View {
  let text: String
  let clearAction: () -> Void
  let sendAction: () -> Void
   
  var body: some View {
    ZStack {
      if text.isEmpty {
        Button("Отправить уведомление", action: sendAction)
          .transition(.move(edge: .bottom).combined(with: .opacity))
      } else {
        VStack(spacing: 20) {
          Text(text).font(.title)
          Button("Очистить", action: clearAction)
        }
        .transition(.slide.combined(with: .opacity).combined(with: .scale))
      }
    }
    .animation(.default, value: text.isEmpty)
  }
}

Пример № 1

Подписываемся на уведомление во вьюхе:

extension NotificationCenterExample {
  struct OnReceiveExample: View {
    @State private var notificationText = ""
     
    var body: some View {
      DemoView(
        text: notificationText,
        clearAction: { notificationText = "" },
        sendAction: {
          NotificationCenter.default.post(
            name: notificationName,
            object: "Привет от NotificationCenter!"
          )
        }
      )
      .onReceive(NotificationCenter.default.publisher(for: notificationName)) { notification in
        if let text = notification.object as? String {
          notificationText = text
        }
      }
    }
  }
}

Пример №2

Работаем со вьюмоделью.

Делаем вьюмодель

final class ViewModel: ObservableObject {
  @Published private(set) var text = ""
  private var cancellable: AnyCancellable?
   
  init() {
    cancellable = NotificationCenter.default
      .publisher(for: notificationName)
      .sink { notification in
        if let text = notification.object as? String {
          self.text = text
        }
      }
  }
   
  deinit { cancellable?.cancel() }
   
  func sendAction() {
    NotificationCenter.default.post(
      name: notificationName,
      object: "Привет от NotificationCenter!"
    )
  }
   
  func clearAction() { text = "" }
}

Делаем экран

extension NotificationCenterExample {   
  struct ViewModelExample: View {
    @StateObject private var viewModel = ViewModel()
     
    var body: some View {
      DemoView(
        text: viewModel.text,
        clearAction: viewModel.clearAction,
        sendAction: viewModel.sendAction
      )
    }
  }
}

Заключение

NotificationCenter может пригодиться в разных ситуациях, в том числе когда нужно быстро реализовать какую-то связку действий для MVP фичи, например.

Также можно подписываться на системные события вроде появления/скрытия клавиатуры, сворачивания/разворачивания приложения.

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