Skip to content

Instantly share code, notes, and snippets.

@cristhianleonli
Created December 12, 2022 21:09
Show Gist options
  • Save cristhianleonli/2a9265de31038bc1e7a77503c0a03496 to your computer and use it in GitHub Desktop.
Save cristhianleonli/2a9265de31038bc1e7a77503c0a03496 to your computer and use it in GitHub Desktop.
//
// ReactiveViewModel.swift
// MVRxVM
//
// Created by Cristhian Leon on 2022.
//
import Foundation
import Combine
protocol ReactiveViewModel {
/// Makes reference to any view state the view model uses.
associatedtype ViewState
/// Since Swift still doens't support wrappingProperties in protocols,
/// this property is required to implement. This won't affect the behavior,
/// rather just satisfies the compiler.
var viewState: Published<ViewState>.Publisher { get }
/// Allows view models be able to map the state into properties,
/// remove duplicates, and receive events on the main queue.
/// This is to force view to run on sink on UI queues.
func stateOf<T: Equatable>(_ transform: @escaping (ViewState) -> T) -> AnyPublisher<T, Never>
}
extension ReactiveViewModel {
func stateOf<T: Equatable>(_ transform: @escaping (ViewState) -> T) -> AnyPublisher<T, Never> {
viewState
// convert the whole state into a property of it.
.map(transform)
// Avoids the view to react multiple times when the value hasn't changed.
.removeDuplicates()
// since this is called ONLY from the UI, receveing on main queue is required.
.receive(on: DispatchQueue.main)
// convert it to any.
.eraseToAnyPublisher()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment