Contents

josshad/signaling

In projects with Rx/Combine there may be a common pattern of sending events/actions to parent view models or coordinators.

RxSwift

import RxSignaling

final class ViewModel {
  enum Action {
    case showAlert
  }

  @Signaling<Action> var actions

  func doSmth() {
    _actions.accept(.showAlert)
  }
}

final class Parent {
  private let viewModel = ViewModel()
  private let disposeBag = DisposeBag()

  init() {
    viewModel.$actions
      .emit(onNext: {
        switch $0 {
          ..
        }
      })
      .disposed(by: disposeBag)
  }
}

Combine

import CombineSignaling

final class ViewModel {
  enum Action {
    case showAlert
  }

  @Signaling<Action> var actions

  func doSmth() {
    _actions.send(.showAlert)
  }
}

final class Parent {
  private let viewModel = ViewModel()
  private let cancallables = Set<AnyCancellable>()

  init() {
    viewModel.$actions
      .sink(receiveValue: {
        switch $0 {
          ..
        }
      })
      .store(in: cancellables)
  }
}

Pros:

  • the code becomes more compact
  • we use common approach to subscribing to $<variable> as with @Publisher property wrapper
  • you can't modify or emit event from outside of ViewModel
  • you can't change property (as you still can do with lazy var in the first approach)

Installation

RxSwift

...
dependencies: [
  .package(url: "https://github.com/josshad/Signaling.git", .upToNextMajor(from: "1.0.0"))
],
targets: [
  .target(
    name: "...",
      dependencies: [
        .product(name: "RxSignaling", package: "signaling")
      ]
  ),
]

Combine

...
dependencies: [
  .package(url: "https://github.com/josshad/Signaling.git", .upToNextMajor(from: "1.0.0"))
],
targets: [
  .target(
    name: "...",
      dependencies: [
        .product(name: "CombineSignaling", package: "signaling")
      ]
  ),
]

Package Metadata

Repository: josshad/signaling

Default branch: main

README: README.md