TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

Array isEmpty when observedobject updated

Forums > SwiftUI

I'm new to SwiftUI and MVVM and have been working on a podcast app and can't figure out for the life of me how to resolve this issue.

I have a list of podcast episodes with a button assigned to each in a VStack, when pressed, updates the userStore and presents a minimized player. When this happens, my list disappears and I get the ActivityIndicator and the list never reappears. I'm guessing the array gets cleared out whenever the state is updated. I don't want this behavior. What am I doing wrong?

struct PodcastDetailView: View {

    @EnvironmentObject var userStore: UserStore
    @ObservedObject var minimizableViewHandler: MinimizableViewHandler
    @ObservedObject var player: Player = Container.player
    @ObservedObject var podcastViewModel: PodcastViewModel

    init(podcast: Podcast, player: Player = Container.player, minimizableViewHandler: MinimizableViewHandler) {
        self.podcastViewModel = PodcastViewModel(podcast: podcast)
        self.player = player
        self.minimizableViewHandler = minimizableViewHandler
    }

    var body: some View {
        ZStack{
            Color(hex: "1B1D26")
                .edgesIgnoringSafeArea([.all])
            VStack(alignment: .leading, spacing: 10) {
                PodcastDetailHeader(podcast: podcastViewModel.podcast)
                if podcastViewModel.episodes.isEmpty {
                    ActivityIndicator()
                        .frame(width: 120, height: 120)
                        .foregroundColor(Color(hex: "813F97"))
                        .opacity(0.8)
                        .animation(.easeOut)
                } else {
                    ScrollView {
                        VStack(alignment: .center, spacing: 10)
                        {
                            ForEach(podcastViewModel.episodes, id: \.self) { episode in 

                                Button(action: {
                                    if (self.player.state == .empty) {
                                        self.userStore.selectedEpisode = episode
                                        var newEpisodeData = self.podcastViewModel.episodes

                                        if let selectedEpisodeIndex = newEpisodeData.firstIndex(where: {$0.id == episode.id}) {
                                            newEpisodeData.remove(at: selectedEpisodeIndex)
                                            newEpisodeData.insert(episode, at: newEpisodeData.startIndex)
                                            self.player.setup(for: newEpisodeData)

                                            self.minimizableViewHandler.present()

                                        } else {
                                            // item could not be found
                                        }
                                    } else {
                                        print("new episode is " + episode.title)
                                        self.userStore.selectedEpisode = episode
                                        var newEpisodeData = self.podcastViewModel.episodes
                                        if let selectedEpisodeIndex = newEpisodeData.firstIndex(where: {$0.id == episode.id}) {
                                            newEpisodeData.remove(at: selectedEpisodeIndex)
                                            newEpisodeData.insert(episode, at: newEpisodeData.startIndex)
                                            self.player.setup(for: newEpisodeData)
                                            self.player.play()
                                        }
                                    }

                                }) {
                                    PodcastRowView(episode: episode)
                                        .fixedSize(horizontal: false, vertical: true)
                                        .padding(.top, 8)

                                }.buttonStyle(PlainButtonStyle())
                                .padding(.leading, 20)
                                .padding(.trailing, 10)

                            }

                        }
                    }

                }
                Spacer()

            }
        }
        .navigationBarBackButtonHidden(true)
        .navigationBarTitle(Text(self.podcastViewModel.podcast.title), displayMode: .inline)

        .onAppear {
            print("appearing")
            self.podcastViewModel.loadEpisodes()
        }

    }

}
import Combine
import SwiftUI

class PodcastViewModel: ObservableObject {

    private let apiService: APIService
    private var episodesCancelable: Cancellable?

    @Published var podcast: Podcast

    @Published var episodes: [Episode] = []

    init(podcast: Podcast, apiService: APIService = APIService()) {
        self.podcast = podcast
        self.apiService = apiService

    }

    deinit {
        episodesCancelable?.cancel()
    }

    func loadEpisodes() {
        episodesCancelable = apiService.episodes(for: podcast)
            .receive(on: RunLoop.main)
            .replaceError(with: [])
            .assign(to: \.episodes, on: self)

    }

}

2      

Solved by using @StateObject instead of @ObservedObject

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.