UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

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.