我正在尝试设置一个名为allCountries的已发布变量。在我的DispatchQueue中,正在设置它,实际上是在向控制台输出正确的信息。在我的内容视图中,数组中什么都没有。在内容视图的init函数中,我正在调用将获取数据并设置变量的函数,但是当我打印到控制台时,该变量为空白。有人可以告诉我我在做什么错吗?
这是我要提取数据的地方
class GetCountries: ObservableObject {
@Published var allCountries = [Countries]()
func getAllPosts() {
guard let url = URL(string: "apiURL")
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)")}}}
答案 0 :(得分:0)
问题发生在您的init
的{{1}}中。您正在调用TYPE的函数ContentView
,但随后尝试访问该类型getAllPosts
的新INSTANCE的数据。您的countries2
实例属性实际上与countries2.allCountries
类型属性没有任何关系。
它甚至可以编译吗?如果要在Type本身而不是在其实例上调用它们,通常需要将类的函数和属性定义为GetCountries.allCountries
。
也许这很奇怪,因为您正在尝试在static
的init中进行此操作,而不是在初始化后进行此操作。
您可能需要做两件事来解决此问题。
第一步是让您的自定义初始化程序实际初始化ContentView
。
第二步是在该自定义初始化程序中调用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)")}}}
初始化程序中遇到异步调用问题。最好是将其移动到加载视图时调用的函数中,而不是在初始化SwiftUI结构时调用该函数。
为此,您可以将网络调用移至ContentView
(而不是其ContentView
)的函数中,然后对视图使用init
修饰符,该修饰符将在以下情况下调用该函数.onAppear
出现。 (现在,我们不使用自定义初始化程序,我们需要返回到初始化NavigationView
属性。)
countries2
请注意这种方法。根据您的UI架构,每次NavigationView出现时,它将调用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
}
}
。如果您对新视图进行getTheCountries
调用,那么如果您返回第一页,则可能会重新加载该视图。但是您可以在NavigationLink
内轻松添加支票,以查看是否确实需要这项工作。
答案 1 :(得分: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 !!
}
}