所以我遇到一个奇怪的问题,在我的视图堆栈中,.onAppear正在运行我的功能以从服务器中提取数据,但是无法显示我为该接口创建的卡片元素。我要实现的目标是,当用户打开应用程序并将其带到仪表板时,它将显示平台的各个标题。我没有收到任何错误,因为可以正确读取JSON对象。
我读到的一些事情是,在调用.onAppear之后,可能需要更新视图,但是我发现的资源并未真正说明如何执行此操作。代码的第一位是我的JSON对象:
{"results" : [{"id":1,"title":"Meet ergoWare","header_image":"http://gba.ergoware.io/cache/content/topstory/ergo_news_01.svg","summary":"GBA's New Ergonomic Portal!"}]}
通过此功能将其拉入
func loadHeadlines(CDNLink: String) {
guard let url = URL(string: CDNLink) else {
print("Invalid URL")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request) { data, response, error in
if error != nil {
print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
return
} else {
do {
let decodedResponse = try JSONDecoder().decode(Response.self, from: data!)
print(decodedResponse)
self.results = decodedResponse.results
} catch let err {
print("Error parsing: \(err)")
}
}
}.resume()
}
然后在.onAppear上标记我的HStack,它执行该功能并像这样运行我的ForEach语句
ScrollView(showsIndicators: false){
Text("HEADLINES")
.font(.system(size: 18))
.fontWeight(.medium)
.foregroundColor(.secondary)
.frame(maxWidth: .infinity, alignment: .leading)
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(results) { result in
CardView(image: result.header_image, heading: result.title, summary: result.summary)
}
}.onAppear(perform:{self.loadHeadlines(CDNLink: "http://\(self.defaults.object(forKey: "domain") as! String)/cdn?funct=fetchNews")})
}
所以我的问题是,为什么场景加载时CardView不显示?使用Simulator,如果我构建并测试了该应用程序,然后退出该应用程序并重新打开,则卡开始显示。感谢您提供的任何见解。下面有一些指向完整代码的链接。
答案 0 :(得分:2)
只是为了阐明init和onAppear()(根据注释进行编码)之间的区别
假设您有一个带有2个视图的TabView。第一个视图是您创建并为其提供代码的视图,第二个视图可以是配置文件视图。每次用户在这两个TabView之间切换时都会调用onAppear()函数,而init()函数在此特定用例中只会运行一次。
接下来,必须注意URLSession在后台线程上运行。您只能从MainThread更新视图,这意味着您应该将结果封装到:
DispatchQueue.main.async {
self.results = decodedResponse.results
}
但是您问题的必答题
几天前我刚刚遇到了同样的问题。 ScrollView目前有一些错误/功能,这意味着,如果您尝试ScrollView + ForEach一个将在以后更新的空数组,它将不会显示。如果您将硬编码的文章作为第一项,然后再更新其余内容,那么它将起作用。我的Atleast在iOS 13.3.1上的swift5 xcode 11.3.1下工作。但是,我使用ObservableObject处理类中的数据,并使用ObservedObject利用@Published修饰符。像这样
class Result : ObservableObject{
@Published var results = [Article]()
}
并将其写入您的swiftUI代码:
@ObservedObject private var data = Result()
您的swiftui初始化函数应包含一个添加函数,例如,绕过ScrollView错误/功能:
init() {
self.data.results.append(....)
self.callYourRestAPIHere(URL:"whateverhere", result: data)
}
希望我什么都没错过,但如果可以的话,我准备改善我的答案。
答案 1 :(得分:1)
我认为您应该在ForEach循环中标识数据,以便SwiftUI可以区分不同的数据项,并可以正确查看数组的内容是否已更改。像这样:
target