当我滚动 SwiftUI/Swift 时,图像在列表中消失 [英] Images disappear in List as I scroll SwiftUI/Swift

查看:29
本文介绍了当我滚动 SwiftUI/Swift 时,图像在列表中消失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我通过获取(获取)图像的路径,然后使用图像路径从该 url/路径中获取图像,将图像添加到我的 SwiftUI 列表中.

So I'm adding an Image to my SwiftUI list by getting(fetching) the path to the image and then using the image path to fetch the image from that url/path.

获取数据/路径

class Webservice {
    func getAllPosts(completion: @escaping ([Post]) -> ()) {
        guard let url = URL(string: "http://localhost:8000/albums")
     else {
     fatalError("URL is not correct!")
    }

        URLSession.shared.dataTask(with: url) { data, _, _ in

            let posts = try!

                JSONDecoder().decode([Post].self, from: data!); DispatchQueue.main.async {
                    completion(posts)
            }
        }.resume()
    }
}

变量

struct Post: Codable, Hashable, Identifiable {

    let id: String
    let title: String
    let path: String
    let description: String
}

Post中的变量设置为class Webservicecompletion(posts)中的posts.>

Setting the variables in Post to the posts in completion(posts) in class Webservice.

final class PostListViewModel: ObservableObject {

    init() {
        fetchPosts()
    }

    @Published var posts = [Post]()

    private func fetchPosts() {
        Webservice().getAllPosts {
            self.posts = $0
        }
    }


}

从网址/路径获取图片

class ImageLoader: ObservableObject {
    var didChange = PassthroughSubject<Data, Never>()
    var data = Data() {
        didSet {
            didChange.send(data)
        }
    }

    init(urlString:String) {
        guard let url = URL(string: urlString) else { return }
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else { return }
            DispatchQueue.main.async {
                self.data = data
            }
        }

        task.resume()
    }
}

设置@State 图像

struct ImageView: View {
    @ObservedObject var imageLoader:ImageLoader
    @State var image:UIImage = UIImage()

    init(withURL url:String) {
        imageLoader = ImageLoader(urlString:url)
    }

    var body: some View {

            Image(uiImage: image)
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width:100, height:100)
                .onReceive(imageLoader.didChange) { data in
                self.image = UIImage(data: data) ?? UIImage()
        }
    }
}

然后使用 ImageView 将我的图像显示在列表中,其中包含我在开头获取的数据的 url/路径,这些数据被传递到 ImageLoader 以获取图像并在 ImageView

Then display my image in a list using ImageView with the url/path from the data I fetched in the beginning which gets passed into ImageLoader to grab the image and set @State image in ImageView

struct ContentView: View {
   init() {
            Webservice().getAllPosts {
                print($0)
            }
        }

    @ObservedObject var model = PostListViewModel()

        var body: some View {

                List(model.posts) { post in
                 VStack {
                    Text(post.title)
                    ImageView(withURL: "http://localhost:8000/\(post.path)")
                    Text(post.description)


                }
            }

        }

}

此代码起初用于获取图像,但是一旦我开始在这里和那里滚动,图像就开始消失.为什么会发生这种情况,我该如何解决?

This code works to get the image at first but once I start scrolling here and there the images start to disappear. Why is this happening and how do I fix it?

我被告知要缓存图像以防止再次加载.有谁知道我会怎么做?

I was told to cache the images to prevent loading again. Does anyone know how I would do that?

推荐答案

图片消失是因为重复使用列表中的单元格,每次单元格重复使用它再次获取图像时,您需要缓存图像以防止它.

disappearing the image is because of reusing cells in the list and every time the cell reused it to fetch the image again, you need to cache the images to prevent it.

您可以通过这种方式更改您的 ImageLoader 并拥有缓存您也需要更改 ImageView 中的图像,而不是 Data 使用 UIImage

you can change your ImageLoader in this way and have a cache you need to change the image in your ImageView too, instead of Data use UIImage

class ImageLoader: ObservableObject {
    @Published var image: UIImage?
    var urlString: String?
    var imageCache = ImageCache.getImageCache()

    init(urlString: String?) {
        self.urlString = urlString
        loadImage()
    }

    func loadImage() {
        if loadImageFromCache() {
            print("Cache hit")
            return
        }

        print("Cache miss, loading from url")
        loadImageFromUrl()
    }

    func loadImageFromCache() -> Bool {
        guard let urlString = urlString else {
            return false
        }

        guard let cacheImage = imageCache.get(forKey: urlString) else {
            return false
        }

        image = cacheImage
        return true
    }

    func loadImageFromUrl() {
        guard let urlString = urlString else {
            return
        }

        let url = URL(string: urlString)!
        let task = URLSession.shared.dataTask(with: url, completionHandler: getImageFromResponse(data:response:error:))
        task.resume()
    }


    func getImageFromResponse(data: Data?, response: URLResponse?, error: Error?) {
        guard error == nil else {
            print("Error: \(error!)")
            return
        }
        guard let data = data else {
            print("No data found")
            return
        }

        DispatchQueue.main.async {
            guard let loadedImage = UIImage(data: data) else {
                return
            }

            self.imageCache.set(forKey: self.urlString!, image: loadedImage)
            self.image = loadedImage
        }
    }
}

缓存类助手

class ImageCache {
    var cache = NSCache<NSString, UIImage>()

    func get(forKey: String) -> UIImage? {
        return cache.object(forKey: NSString(string: forKey))
    }

    func set(forKey: String, image: UIImage) {
        cache.setObject(image, forKey: NSString(string: forKey))
    }
}

extension ImageCache {
    private static var imageCache = ImageCache()
    static func getImageCache() -> ImageCache {
        return imageCache
    }
}

图像视图结构:


struct ImageView: View {
    @ObservedObject var imageLoader:ImageLoader

    init(withURL url:String) {
        imageLoader = ImageLoader(urlString:url)
    }

    var body: some View {

            Image(imageLoader.image ?? UIImage() )
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width:100, height:100)
    }
}

这篇关于当我滚动 SwiftUI/Swift 时,图像在列表中消失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆