【问题标题】:Asynchronous Image Loading Bug异步图像加载错误
【发布时间】:2020-09-24 17:07:18
【问题描述】:

在异步图像加载方面,我遇到了一个奇怪的错误,当我进入一个视图时,它会按预期显示,然后由于某种原因图像下降,我看到的只是“正在加载。 ..”占位符。我在构建加载程序时使用了this tutorial,以下脚本是我的文章视图。我有一个全局函数文件,其中包括对整个应用程序中各种函数的组合和基础的引用。我只是不完全理解为什么图像会短暂显示,然后调用占位符。谢谢!

import SwiftUI

struct ArticleView: View {
    @Environment(\.imageCache) var cache: ImageCache
    var articleID: Int
    @ObservedObject private var data = Result2()
    let defaults = UserDefaults.standard
    
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    
    init(articleID: Int){
        self.articleID = articleID
        self.data.results.append(Story.init(id: 0, title: "test", image: "", story: "", published: "", author: ""))
        self.loadArticle(CDNLink: "http://\(self.defaults.object(forKey: "domain") as! String)/cdn?funct=fetchArticle&articleID=\(self.articleID)")
    }
    
    var backBtn: some View {
        Button(action: {
            self.presentationMode.wrappedValue.dismiss()
        }, label:{
            Image(systemName: "lessthan.circle")
                .resizable()
                .frame(width: 30, height: 30)
                .foregroundColor(Color.primaryRed)
                .padding(.top, 6)
                .padding(.leading, 10)
        })
    }
    
    var body: some View {
        VStack(alignment: .leading){
            ScrollView {
                ForEach(data.results, id: \.id) { result in
                Group{
                    AsyncImage(
                        url: URL(string: result.image)!,
                        placeholder: Text("Loading..."), configuration: { $0.resizable() })
                        .frame(height: 250)
                        .aspectRatio(contentMode: .fill)
                    VStack(alignment: .leading) {
                        Text("\(result.title)")
                            .font(.system(size: 18))
                            .fontWeight(.heavy)
                            .foregroundColor(.primary)
                            .multilineTextAlignment(.leading)
                        HStack {
                            Text("\(result.author)")
                                .font(.system(size: 12))
                                .foregroundColor(.secondary)
                                .multilineTextAlignment(.leading)
                            Text("|")
                                .font(.system(size: 12))
                                .foregroundColor(.secondary)
                                .multilineTextAlignment(.leading)
                            Text("\(result.published)")
                                .font(.system(size: 12))
                                .foregroundColor(.secondary)
                                .multilineTextAlignment(.leading)
                        }.frame(width: UIScreen.main.bounds.size.width - 40, alignment: .leading)
                    }.frame(width: UIScreen.main.bounds.size.width - 40)
                }
                    Text("\(result.story)")
                }
            }
        }
        .frame(maxWidth: .infinity)
        .navigationBarBackButtonHidden(true)
        .navigationBarItems(leading: backBtn)
    }

    func loadArticle(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(Response2.self, from: data!)
                print(decodedResponse)
                DispatchQueue.main.async {
                    self.data.results.append(contentsOf: decodedResponse.results)
                    self.data.results.remove(at: 0)
                }
                } catch let err {
                    print("Error parsing: \(err)")

                }
            }
        }.resume()
    }
}

struct Response2: Codable {
    var results: [Story]
}

struct Story: Codable, Identifiable {
    var id: Int
    var title: String
    var image: String
    var story: String
    var published: String
    var author: String
}

struct ArticleView_Previews: PreviewProvider {
    static var previews: some View {
        ArticleView(articleID: 0)
    }
}

编辑:我已经进行了建议的更改,但我仍然看到错误,您可以通过查看 this link 实时查看错误。

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:

    您好,很可能是因为您使用的是@ObservedObject。每次视图状态更改并触发视图重新渲染时,都会丢弃并初始化此对象。尝试使用@StateObject 而不是@ObservedObject@StateObject 只会在视图中初始化一次。

    @StateObject 也可以与ObservedObject 模型一起使用。它是@ObservedObject@State 的组合。

    【讨论】:

    • 甜,我试一试,数据附加到我的结果中的方式是否完全相同?
    • 如果你的结果是 StateObject 的一个属性,那么它将被附加并且只实例化一次。
    • 是的,但我需要从使用 Init 切换到 .onAppear{} 对吗?这样,当视图加载时,它将加载数据并附加 StateObject。编辑:在这样做的过程中,我仍然看到图像闪烁的相同错误,然后默认返回“正在加载...”
    【解决方案2】:

    好的,所以我创建了一个新的解决方案来修补这个问题,我很高兴这个小工作正在奏效。因此,我开始研究如何在服务器端优化被拉入应用程序的内容。我所做的是使用 PHP 使用 base64 对图像进行编码,然后应用程序将其拉入并解码 base64 数据,图像以闪电般的速度填充!

    服务器端代码:

    $article['image'] = base64_encode(file_get_contents(PATH . "/cache/content/topstory/" . $row['app_article']));
    

    客户端代码:

    let dataDecoded:NSData = NSData(base64Encoded: result.image, options: NSData.Base64DecodingOptions(rawValue: 0))!
    let decodedimage:UIImage = UIImage(data: dataDecoded as Data)!
    Image(uiImage: decodedimage)
       .frame(height: 250)
       .aspectRatio(contentMode: .fill)
    

    【讨论】:

      猜你喜欢
      • 2011-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多