当我滚动 SwiftUI/Swift 时,图像在列表中消失 [英] Images disappear in List as I scroll 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 Webservice
中completion(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屋!