How to access ApplicationMusicPlayer.shared.state in an ObservableObject class?

I am aware that ApplicationMusicPlayer.shared.state is implemented as an observed object, but I'm wondering if it's possible to store that instance in a class annotated with ObservableObject so that I can use objectWillChance or other properties and then forward the values and state I care about view @Published properties. I'm thinking something like this:

class SomeViewModel: ObservableObject {
    @Published var isPlaying: Bool = false

    init() {
        ApplicationMusicPlayer.shared.state.objectWillChange.sink { [self]
            isPlaying = ApplicationMusicPlayer.shared.state.playbackStatus == .playing
        }
    }
}

If I create this class and stick in a SwiftUI View I can see the init being called, but the objectWillChange never seems to fire.

I can however do this and it seems to work inside of the SwiftUI View:

struct SomeView: View {
    @ObservedObject private var playerState = ApplicationMusicPlayer.shared.state
    @State private var isPlaying: Bool = false
    var cancellableBag = Set<AnyCancellable>()

    init() {
        self.isPlaying = playerState.playbackStatus == .playing
        playerState.objectWillChange.sink { [self] in
            print(playerState.playbackStatus)
        }.store(in: &cancellableBag)
    }
}

interesting objectWillChange fires twice for every state update, but I could deal with that if I could just use my own ObservableObject. I'd rather my music player not be so tightly coupled to the view I'm writing.

Answered by DTS Engineer in 739780022

I think your first attempt is correct, except that you forgot to keep a reference to the AnyCancellable value returned from the sink call. That means your subscription is immediately cancelled, and you'll get no future updates.

I can relate to your queries, as I faced them too. I am currently using this:

class SomeViewModel: ObservableObject {
    @Published var state = ApplicationMusicPlayer.shared.state
}

But as you mentioned, it is interesting that objectWillChange fires twice for every state update. It is more visible when you use the queue, and try to observe the changes in the currentEntry, which fires more than twice sometimes.

Accepted Answer

I think your first attempt is correct, except that you forgot to keep a reference to the AnyCancellable value returned from the sink call. That means your subscription is immediately cancelled, and you'll get no future updates.

How to access ApplicationMusicPlayer.shared.state in an ObservableObject class?
 
 
Q