简体   繁体   中英

SwiftUI ScrollView doesn't show fetched results from an ObservableObject

I am trying to fetch data from an api by clicking on a 'Fetch' button and show them via an ForEach loop in a ScrollView.

I am using MVVM Model. The fetch itself happens in an ObservableObject class.

Unfortunately the ScrollView does not show the content. If I am using a List instead of a ScrollView it works fine.

Do you have any idea what I am missing here?

Thank you a lot for your help!

import SwiftUI

struct Photo: Identifiable, Decodable {

    let id = UUID()
    let title: String
}

class ContentViewModel: ObservableObject {

    let api = "https://jsonplaceholder.typicode.com/photos"

    @Published var photos: [Photo] = []

    func fetchData() {
        print("Fetching started")
        guard let url = URL(string: api) else { return }

        URLSession.shared.dataTask(with: url) { data, _, _ in
            DispatchQueue.main.async {
                self.photos = try! JSONDecoder().decode([Photo].self, from: data!)
                print("Fetching successfull. Fetched \(self.photos.count) photos.")
            }
        }.resume()
    }
}

struct ContentView: View {

    @ObservedObject var contentVM = ContentViewModel()

    var body: some View {
        NavigationView {
            ScrollView {
                ForEach(self.contentVM.photos) { photo in
                    Text(photo.title)
                }
            }
            .navigationBarTitle("Home")
            .navigationBarItems(trailing: Button(action: {

                self.contentVM.fetchData()

                }, label: {
                    Text("Fetch")
            }))
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

You didn't miss anything, the problem is with renders content, I think. even in your example data displays on real device (iPhone 7 iOS 13.1.1), but with long delay. Try with less content or help ScrollView with alignment. I tried this - on device works faster, but only on device:

class ContentViewModel: ObservableObject {

    let api = "https://jsonplaceholder.typicode.com/photos"

    @Published var photos: [Photo] = []
    @Published var first100Photos: [Photo] = []

    func fetchData() {
        print("Fetching started")
        guard let url = URL(string: api) else { return }

        URLSession.shared.dataTask(with: url) { data, _, _ in
            DispatchQueue.main.async {
                self.photos = try! JSONDecoder().decode([Photo].self, from: data!)
                for index in 0...100 {
                    self.first100Photos.append(self.photos[index])
                }
                print("Fetching successfull. Fetched \(self.photos.count) photos.")
            }
        }.resume()
    }
}

struct ContentView: View {

    @ObservedObject var contentVM = ContentViewModel()

    var body: some View {
        NavigationView {
            ScrollView(.vertical) {
                VStack {
                    ForEach(self.contentVM.first100Photos) { photo in
                        Text(photo.title)
                    }
                }

            }
            .navigationBarTitle("Home")
            .navigationBarItems(trailing: Button(action: {

                self.contentVM.fetchData()

                }, label: {
                    Text("Fetch")
            }))
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM