SwiftUI:如何获取要显示的服务器数据?

SwiftUI:如何获取要显示的服务器数据?,swiftui,combine,Swiftui,Combine,场景:从服务器访问数据(大小可变)并显示它。在这种情况下,需要一系列国家 进入此视图(或之前)时,应调用服务器访问一次(1) 观察:我可以通过发布服务器中的调试器和打印语句查看数据 问题:视图中不显示数据 下面是完整的代码(简化为一个简单的请求,通过Playder请求一系列国家) 请随意剪切/粘贴到操场上 它应该按预期运行,但不显示任何数据 解决方案? 您不需要额外的状态appleData-它未填充-直接使用appleCountries,如下所示 使用Xcode 12.1/iOS 14.1进行

场景:从服务器访问数据(大小可变)并显示它。在这种情况下,需要一系列国家

进入此视图(或之前)时,应调用服务器访问一次(1)

观察:我可以通过发布服务器中的调试器和打印语句查看数据

问题:视图中不显示数据

下面是完整的代码(简化为一个简单的请求,通过Playder请求一系列国家)

请随意剪切/粘贴到操场上
它应该按预期运行,但不显示任何数据

解决方案?


您不需要额外的状态
appleData
-它未填充-直接使用
appleCountries
,如下所示

使用Xcode 12.1/iOS 14.1进行测试


当我删除“.appleData”时,我得到以下警告:泛型结构“ForEach”要求“AppleCountries”符合“RandomAccessCollection”
import Combine
import SwiftUI
import PlaygroundSupport

// ---------------------------------------------------------------------------

var cancellables: Set<AnyCancellable> = []

struct VaccinesDataView: View {
    @State private var appleData: [String]?
    @StateObject var appleCountries = AppleCountries()

    var body: some View {
        Form {
            Section(header: VStack(alignment: .leading) {
                Text("Apple Data")
            }) {
                if let vacData = appleData {
                    ForEach(vacData, id: \.self) { source in

                        HStack {
                            Text(source)
                                .font(.title)
                        }
                    }
                }
            }
            .navigationBarTitle("Vaccines", displayMode: .inline)
        }.onAppear {
            self.appleCountries.getData()
        }

        .navigationViewStyle(StackNavigationViewStyle())
    }
}

// =====================================================================================================

class AppleCountries: ObservableObject {
    @Published var appleData: [String]?

    func getData() {
        let appleURL = URL(string: "https://disease.sh/v3/covid-19/apple/countries")!
        let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: appleURL)
            .map(\.data)
            .receive(on: DispatchQueue.main)
            .decode(type: [String].self, decoder: JSONDecoder())
            .print("Apples: ")

        remoteDataPublisher
            .eraseToAnyPublisher()
            .sink(receiveCompletion: { completion in
                switch completion {
                case .finished:
                    print("Publisher Finished")
                case let .failure(anError):
                    Swift.print("\nReceived error: ", anError)
                }
            }, receiveValue: { someValue in
                self.appleData = someValue
                print("appleData: \(String(describing: self.appleData))")
            }).store(in: &cancellables)
    }
}

PlaygroundPage.current.setLiveView(VaccinesDataView())
Apples: : receive subscription: (Decode)
Apples: : request unlimited
Apples: : receive subscription: (Decode)
Apples: : request unlimited
Apples: : receive subscription: (Decode)
Apples: : request unlimited
Apples: : receive subscription: (Decode)
Apples: : request unlimited
Apples: : receive value: (["Albania", "Argentina", "Australia", "Austria", "Belgium", "Brazil", "Bulgaria", "Cambodia", "Canada", "Chile", "Colombia", "Croatia", "Czechia", "Denmark", "Egypt", "Estonia", "Finland", "France", "Germany", "Greece", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Ireland", "Israel", "Italy", "Japan", "Latvia", "Lithuania", "Luxembourg", "Macao", "Malaysia", "Mexico", "Morocco", "Netherlands", "New Zealand", "Norway", "Philippines", "Poland", "Portugal", "S. Korea", "Romania", "Russia", "Saudi Arabia", "Serbia", "Singapore", "Slovakia", "Slovenia", "South Africa", "Spain", "Sweden", "Switzerland", "Taiwan", "Thailand", "Turkey", "Ukraine", "UAE", "UK", "USA", "Uruguay", "Vietnam"])
appleData: Optional(["Albania", "Argentina", "Australia", "Austria", "Belgium", "Brazil", "Bulgaria", "Cambodia", "Canada", "Chile", "Colombia", "Croatia", "Czechia", "Denmark", "Egypt", "Estonia", "Finland", "France", "Germany", "Greece", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Ireland", "Israel", "Italy", "Japan", "Latvia", "Lithuania", "Luxembourg", "Macao", "Malaysia", "Mexico", "Morocco", "Netherlands", "New Zealand", "Norway", "Philippines", "Poland", "Portugal", "S. Korea", "Romania", "Russia", "Saudi Arabia", "Serbia", "Singapore", "Slovakia", "Slovenia", "South Africa", "Spain", "Sweden", "Switzerland", "Taiwan", "Thailand", "Turkey", "Ukraine", "UAE", "UK", "USA", "Uruguay", "Vietnam"])
Apples: : receive finished
Publisher Finished
Apples: : receive value: (["Albania", "Argentina", "Australia", "Austria", "Belgium", "Brazil", "Bulgaria", "Cambodia", "Canada", "Chile", "Colombia", "Croatia", "Czechia", "Denmark", "Egypt", "Estonia", "Finland", "France", "Germany", "Greece", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Ireland", "Israel", "Italy", "Japan", "Latvia", "Lithuania", "Luxembourg", "Macao", "Malaysia", "Mexico", "Morocco", "Netherlands", "New Zealand", "Norway", "Philippines", "Poland", "Portugal", "S. Korea", "Romania", "Russia", "Saudi Arabia", "Serbia", "Singapore", "Slovakia", "Slovenia", "South Africa", "Spain", "Sweden", "Switzerland", "Taiwan", "Thailand", "Turkey", "Ukraine", "UAE", "UK", "USA", "Uruguay", "Vietnam"])
appleData: Optional(["Albania", "Argentina", "Australia", "Austria", "Belgium", "Brazil", "Bulgaria", "Cambodia", "Canada", "Chile", "Colombia", "Croatia", "Czechia", "Denmark", "Egypt", "Estonia", "Finland", "France", "Germany", "Greece", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Ireland", "Israel", "Italy", "Japan", "Latvia", "Lithuania", "Luxembourg", "Macao", "Malaysia", "Mexico", "Morocco", "Netherlands", "New Zealand", "Norway", "Philippines", "Poland", "Portugal", "S. Korea", "Romania", "Russia", "Saudi Arabia", "Serbia", "Singapore", "Slovakia", "Slovenia", "South Africa", "Spain", "Sweden", "Switzerland", "Taiwan", "Thailand", "Turkey", "Ukraine", "UAE", "UK", "USA", "Uruguay", "Vietnam"])
Apples: : receive finished
Publisher Finished
...
...
...
struct VaccinesDataView: View {
    @StateObject var appleCountries = AppleCountries()

    var body: some View {
        Form {
            Section(header: VStack(alignment: .leading) {
                Text("Apple Data")
            }) {
                if let vacData = appleCountries.appleData {    //  !!
                    ForEach(vacData, id: \.self) { source in

                        HStack {
                            Text(source)
                                .font(.title)
                        }.onAppear {
                            appleCountries.getData()
                        }
                    }
                }
            }
            .navigationBarTitle("Vaccines", displayMode: .inline)
        }.onAppear {
            self.appleCountries.getData()
        }

        .navigationViewStyle(StackNavigationViewStyle())
    }
}