onAppear不显示界面元素

时间:2020-03-07 16:35:44

标签: swift swiftui

所以我遇到一个奇怪的问题,在我的视图堆栈中,.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,如果我构建并测试了该应用程序,然后退出该应用程序并重新打开,则卡开始显示。感谢您提供的任何见解。下面有一些指向完整代码的链接。

Dashboard View CardView

2 个答案:

答案 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