gpt4 book ai didi

SwiftUI 列表 - 远程图像加载 = 图像闪烁(重新加载)

转载 作者:行者123 更新时间:2023-12-04 10:32:35 25 4
gpt4 key购买 nike

我是 SwiftUI 的新手,也是 Combine 的新手。我有一个简单的列表,我正在加载 iTunes 数据并构建列表。加载图像有效 - 但它们在闪烁,因为我在主线程上的调度似乎一直在触发。我不确定为什么。下面是图像加载的代码,然后是它的实现位置。

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

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

func imageFromData(_ data: Data) -> UIImage {
UIImage(data: data) ?? UIImage()
}

var body: some View {
VStack {
Image(uiImage: imageLoader.dataIsValid ?
imageFromData(imageLoader.data!) : UIImage())
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:60, height:60)
.background(Color.gray)
}
}
}

class ImageLoaderNew: ObservableObject
{
@Published var dataIsValid = false
var data: Data?

// The dispatch fires over and over again. No idea why yet
// this causes flickering of the images in the List.
// I am only loading a total of 3 items.

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.dataIsValid = true
self.data = data
print(response?.url as Any) // prints over and over again.
}
}
task.resume()
}
}

而这里是在加载JSON等之后实现的。

List(results, id: \.trackId) { item in
HStack {

// All of these image end up flickering
// every few seconds or so.
ImageView(withURL: item.artworkUrl60)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 5))

VStack(alignment: .leading) {
Text(item.trackName)
.foregroundColor(.gray)
.font(.headline)
.truncationMode(.middle)
.lineLimit(2)

Text(item.collectionName)
.foregroundColor(.gray)
.font(.caption)
.truncationMode(.middle).lineLimit(1)
}
}
}
.frame(height: 200.0)
.onAppear(perform: loadData) // Only happens once

我不确定为什么图像会一遍又一遍地加载(至今)。我一定是遗漏了一些简单的东西,但我绝对不了解 Combine 的方法。任何见解或解决方案将不胜感激。

最佳答案

我会改变分配的顺序如下(因为否则 dataIsValid 强制刷新,但 data 尚未设置)

DispatchQueue.main.async {
self.data = data // 1) set data
self.dataIsValid = true. // 2) notify that data is ready

其他一切似乎都不重要。但是考虑下面优化的可能性,因为 UIImage 从数据构建可能也足够长(对于 UI 线程)

func imageFromData(_ data: Data) -> UIImage {
UIImage(data: data) ?? UIImage()
}

所以我建议不仅将数据,而且将整个图像构建移动到后台线程中,并且仅在最终图像准备就绪时才刷新。

更新:我已经让您的代码快照在本地工作,当然有一些替换和简化,因为并非所有部分最初都可用,并提出了上述修复。下面是一些实验结果:

enter image description here

如您所见,没有观察到闪烁,也没有重复登录控制台。由于我没有对您的代码逻辑进行任何重大更改,因此我认为导致报告的闪烁的问题不在提供的代码中 - 可能其他一些部分导致重新创建产生这种效果的 ImaveView

这是我的代码(完整,使用 Xcode 11.2/3 和 iOS 13.2/3 测试):

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

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

func imageFromData(_ data: Data) -> UIImage {
UIImage(data: data) ?? UIImage()
}

var body: some View {
VStack {
Image(uiImage: imageLoader.dataIsValid ?
imageFromData(imageLoader.data!) : UIImage())
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width:60, height:60)
.background(Color.gray)
}
}
}

class ImageLoaderNew: ObservableObject
{
@Published var dataIsValid = false
var data: Data?

// The dispatch fires over and over again. No idea why yet
// this causes flickering of the images in the List.
// I am only loading a total of 3 items.

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
self.dataIsValid = true
print(response?.url as Any) // prints over and over again.
}
}
task.resume()
}
}

struct TestImageFlickering: View {
@State private var results: [String] = []
var body: some View {
NavigationView {
List(results, id: \.self) { item in
HStack {

// All of these image end up flickering
// every few seconds or so.
ImageView(withURL: item)
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 5))

VStack(alignment: .leading) {
Text("trackName")
.foregroundColor(.gray)
.font(.headline)
.truncationMode(.middle)
.lineLimit(2)

Text("collectionName")
.foregroundColor(.gray)
.font(.caption)
.truncationMode(.middle).lineLimit(1)
}
}
}
.frame(height: 200.0)
.onAppear(perform: loadData)
} // Only happens once
}

func loadData() {
var urls = [String]()
for i in 1...10 {
urls.append("https://placehold.it/120.png&text=image\(i)")
}
self.results = urls
}
}

struct TestImageFlickering_Previews: PreviewProvider {
static var previews: some View {
TestImageFlickering()
}
}

关于SwiftUI 列表 - 远程图像加载 = 图像闪烁(重新加载),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60346009/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com