onAppear不显示界面元素



所以我遇到了一个奇怪的问题,在我的视图堆栈中,.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()
    }

然后加上标签。on出现在我的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不显示?使用模拟器,如果我构建并测试应用程序,然后退出应用程序并返回,卡片就会开始显示。感谢您提供的任何见解。下面我有一些链接到我的完整代码。

仪表板视图CardView

只是为了澄清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 init函数应该包含这样的添加函数,以绕过ScrollView错误/功能:

init() {
    self.data.results.append(....)
    self.callYourRestAPIHere(URL:"whateverhere", result: data)
}

希望我没有错过任何东西,但如果我错过了,我准备改进我的答案。

我认为您应该识别ForEach循环中的数据,这样SwiftUI就可以区分不同的数据项,并可以正确地查看数组的内容是否已经更改。像这样:

ForEach(results, id: .id) { result in
    CardView(image: result.header_image, heading: result.title, summary: result.summary)
}

最新更新