SwiftUI发布的变量未更新

问题描述 投票:1回答:2

我正在尝试设置一个名为allCountries的已发布变量。在我的DispatchQueue中,正在设置它,实际上是在向控制台输出正确的信息。在我的内容视图中,数组中什么都没有。在内容视图的init函数中,我正在调用将获取数据并设置变量的函数,但是当我打印到控制台时,该变量为空白。有人可以告诉我我在做什么错吗?

这里是我获取数据的地方

class GetCountries: ObservableObject {

@Published var allCountries = [Countries]()

func getAllPosts() {

    guard let url = URL(string: "http://test.stonhard.com/umbraco/api/products/getlanguages")
        else {
            fatalError("URL does not work!")
    }

    URLSession.shared.dataTask(with: url) { data, _, _ in
        do {
            if let data = data {
                let posts = try JSONDecoder().decode([Countries].self, from: data)


                DispatchQueue.main.async {

                    self.allCountries = posts
                    print(self.allCountries)

                }
            } else  {
                DispatchQueue.main.async {
                    print("didn't work")
                }
            }
        }
        catch {
            DispatchQueue.main.async {
                print(error.localizedDescription)
            }
        }

    }.resume()
}

}

这是我的内容视图

struct ContentView: View {

var countries = ["Select Your Country", "Canada", "Mexico", "United States"]

@ObservedObject var countries2 = GetCountries()

@State private var selectedCountries = 0

init() {
    GetCountries().getAllPosts()
    print(countries2.allCountries)

}

var body: some View {
    NavigationView {

        ZStack {

            VStack {
                Text("\(countries2.allCountries.count)")}}}
swift swiftui swift5
2个回答
0
投票

问题出现在initContentView中。您正在调用TYPE的函数getAllPosts,但随后尝试访问该类型countries2的新INSTANCE的数据。您的countries2.allCountries实例属性实际上与GetCountries.allCountries类型属性没有关系。

甚至可以编译吗?如果要在Type本身而不是在其实例上调用它们,通常需要将类的函数和属性定义为static

也许这很奇怪,因为您正在尝试在ContentView的init中进行此操作,而不是在初始化后进行。

可能需要做两件事来解决这个问题。

第一步是让您的自定义初始化程序实际初始化countries2

第二步是在该自定义初始化程序中调用countries2.getAllPosts,它将填充您尝试在countries2.allCountries中访问的实例属性。

尝试一下:

struct ContentView: View {

var countries = ["Select Your Country", "Canada", "Mexico", "United States"]

// You'll initialize this in the custom init
@ObservedObject var countries2: GetCountries

@State private var selectedCountries = 0

init() {
    countries2 = GetCountries()
    countries2.getAllPosts()
    print(countries2.allCountries)

}

var body: some View {
    NavigationView {

        ZStack {

            VStack {
                Text("\(countries2.allCountries.count)")}}}

但是我不确定您是否会在ContentView初始化程序中遇到异步调用问题。最好是将其移动到加载视图时调用的函数中,而不是在初始化SwiftUI结构时调用该函数。

为此,将网络调用移到ContentView的功能中(而不是init的功能),然后对视图使用.onAppear修饰符,当NavigationView出现时,该修饰符将调用一个功能。 (现在,我们不使用自定义初始化程序,我们需要返回到初始化countries2属性。)

struct ContentView: View {

    var countries = ["Select Your Country", "Canada", "Mexico", "United States"]

    // We're initializing countries2 again
    @ObservedObject var countries2 = GetCountries()

    @State private var selectedCountries = 0

    // This is the function that will get your country data
    func getTheCountries() {
        countries2.getAllPosts()
        print(countries2.allCountries)

    }

    var body: some View {
        NavigationView {
            ZStack {
                VStack {
                    Text("\(countries2.allCountries.count)")
                }
            }
        }
        .onAppear(perform: getTheCountries) // Execute this when the NavigationView appears
    }
}

注意这种方法。根据您的UI架构,每次出现NavigationView时,它将调用getTheCountries。如果您对新视图进行NavigationLink调用,那么如果您返回此第一页,则可能会重新加载该视图。但是您可以轻松地在getTheCountries中添加检查,以查看是否确实需要执行工作。


0
投票

应该使用同一实例来发起请求并读取结果,因此这是固定的变体:

struct ContentView: View {

    var countries = ["Select Your Country", "Canada", "Mexico", "United States"]

    @ObservedObject var countries2 = GetCountries()   // member
    @State private var selectedCountries = 0

    init() {
        // GetCountries().getAllPosts()      // [x] local variable
        // print(countries2.allCountries)
    }

    var body: some View {
        NavigationView {
            ZStack {
                VStack {
                    Text("\(countries2.allCountries.count)")
                }
            }
        }
        .onAppear { self.countries2.getAllPosts() } // << here !!
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.