因此,我要通过获取(获取)图像的路径,然后使用图像路径从该url /路径获取图像,将图像添加到我的SwiftUI列表中。
抓取数据/路径
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
中的变量设置为completion(posts)
中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
中以获取图像并设置@State图像在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)
}
}
}
}
此代码起初是用来获取图像的,但是一旦我开始滚动到此处,图像就会开始消失。为什么会发生这种情况,我该如何解决?
编辑:有人告诉我缓存图像以防止再次加载。有人知道我会怎么做吗?
答案 0 :(得分:2)
消失的图像是由于重复使用列表中的单元格,并且每次单元格重新使用它来再次获取图像时,都需要缓存图像以防止出现。
您可以通过这种方式更改ImageLoader并具有缓存 您还需要在ImageView中更改图像,而不是使用UIImage来代替数据
select t.*, pow(c1 - 8, 2) + pow(c2 - 5, 2) as distance_squared
from test t
order by distance_squared
limit 3
缓存类助手
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
}
}
}
ImageView结构:
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
}
}