Using .run and await in to observe AnyPublisher<Value, Never> does not work

Hey,

I currently do have some Issues related to long living effects.

To give you some background:
I created a Dependency to observe a specific value from the UserDefaults.
It returns an AnyPublisher we can subscribe to, to get notified when the value changes.


enum CardMode: String, Codable, CaseIterable {
    case expanded
    case collapsed
}

struct CardModeProvider {
    var cardMode: () -> CardMode
    var cardModePublisher: AnyPublisher<CardMode, Never>
    var storeCardMode: (CardMode) -> Void
}

extension CardModeProvider {
    static let live: CardModeProvider = {
        return Self(
            cardMode: {
                CardMode(rawValue: UserDefaults.sharedGroupDefaults.cardMode) ?? .expanded
            },
            cardModePublisher: UserDefaults.sharedGroupDefaults
                .publisher(for: \.cardMode)
                .map { CardMode(rawValue: $0) ?? .expanded }
                .eraseToAnyPublisher(),
            storeCardMode: {
                UserDefaults.sharedGroupDefaults.cardMode = $0.rawValue
            }
        )
    }()
}

private enum CardModeDependencyKey: DependencyKey {
    static let liveValue = CardModeProvider.live
}

extension DependencyValues {
  var cardModeProvider: CardModeProvider {
    get { self[CardModeDependencyKey.self] }
    set { self[CardModeDependencyKey.self] = newValue }
  }
}

Inside the reducer I observed the value changes using eraseToEffect:

func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
    switch action {
        case .onAppear:
            return cardModeProvider.cardModePublisher.eraseToEffect {
                .updateCardMode($0)
            }
    }
}

it works like a charm but after I took a look into the Docs I discovered that it is recommended to use .run and for await value in sequence for that. So I tried to do that.

.run { send in
    for await value in cardModeProvider.cardModePublisher.values {
        await send(.updateCardMode(value))
    }
}

But unfortunately I doesn't work as expected.
It will get triggered once, but each time I change the value in the User-Defaults the action will not get send.
I first assumed that my publisher was cancelled or completed somehow under the hood so I tried to investigate using handleEvents.

static let live: CardModeProvider = {
        return Self(
            cardMode: {
                CardMode(rawValue: UserDefaults.sharedGroupDefaults.cardMode) ?? .expanded
            },
            cardModePublisher: UserDefaults.sharedGroupDefaults
                .publisher(for: \.cardMode)
                .handleEvents(receiveCompletion: {
                    // ...
                }, receiveCancel: {
                    // ...
                })
                .map { CardMode(rawValue: $0) ?? .expanded }
                .eraseToAnyPublisher(),
            storeCardMode: {
                UserDefaults.sharedGroupDefaults.cardMode = $0.rawValue
            }
        )
  }()

But it turned out that none of those publisher events occur.
Does anyone maybe has an idea what I am doing wrong?

Hey! Have you tried to implement it by setting a closure returning an AsyncStream<Event> as the cardModePublisher type? You can check a small example here at the docs.