Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton publisher with binding to multiple views

Overview

My app has the feature of favorit-ing objects. There are multiple views that require access to [Favorite] to render UI as well as adding and removing them.

I would like to have a single source of [Favorite] where:

  1. all views render UI based on it
  2. updating this source signals all views subscribed to it and rerender based on the updated value
  3. on each update, the source is persisted in UserDefaults
  4. updating favorites from UI also updates the Singleton's source, therefore signally other views to update

Attempt 1

I attempted to use @Binding to link the the source but it does not update UI when the source is changed.

class Singleton {
    static let shared = Singleton()

    var favorites = CurrentValueSubject<[Favorite], Never>(someFavorites)
}


class ViewModel: ObservableObject {
    @Binding var favorites: [Favorite]

    init() {
        _favorites = Binding<[Favorite]>(get: { () -> [Favorite] in
            Singleton.shared.favorites.value
        }, set: { newValue in
            Singleton.shared.favorites.send(newValue)
        })
    }
}

Attempt 2

I've also attempted creating the binding using Publishers and Subscribers but that ends up in an infinite loop.


Thanks in advance

like image 462
Norman Lim Avatar asked Sep 01 '25 22:09

Norman Lim


1 Answers

Here is possible approach. Tested with Xcode 11.5b2.

class Singleton {
    static let shared = Singleton()

    // configure set initial value as needed, [] used for testing
    var favorites = CurrentValueSubject<[Favorite], Never>([])
}


class ViewModel: ObservableObject {
    @Published var favorites: [Favorite] = []

    private var cancellables = Set<AnyCancellable>()

    init() {
        Singleton.shared.favorites
            .receive(on: DispatchQueue.main)
            .sink { [weak self] values in
                self?.favorites = values
            }
            .store(in: &cancellables)
    }
}
like image 117
Asperi Avatar answered Sep 03 '25 16:09

Asperi