我正在尝试显示带有图片的用户列表。这是代码
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UserListTableViewCell
let message = messages[indexPath.row]
cell.message = message
return cell
}
在UserListTableViewCell文件中,我正在下载图像(也使用缓存)并在桌面上显示它。但我发现有些行有重复/重复的图像。重新加载后重复消失,但它的背面垂直滚动。
这是UserListTableViewCell文件:
import UIKit
import Firebase
class UserListTableViewCell: UITableViewCell {
@IBOutlet weak var username: UILabel!
@IBOutlet weak var textMessage: UILabel!
@IBOutlet weak var timeLabel: UILabel!
@IBOutlet weak var userImage: UIImageView!
var message: Message? {
didSet {
if let id = message?.chatPartnerID() {
let database = Database.database().reference()
let ref = database.child("Users").child(id)
ref.observeSingleEvent(of: .value, with: {
(snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
self.username.text = dictionary["username"] as? String
if let profileImageUrl = dictionary["image"] as? String, profileImageUrl != "" {
self.userImage.image = UIImage(named: "blank-user")
self.userImage.loadImageFromCacheWithUrlString(urlString: profileImageUrl)
self.userImage.layer.cornerRadius = self.userImage.frame.size.width/2
self.userImage.clipsToBounds = true
} else {
self.userImage.image = UIImage(named: "blank-user")
self.userImage.layer.cornerRadius = self.userImage.frame.size.width/2
self.userImage.clipsToBounds = true
}
}
}, withCancel: nil)
}
textMessage.text = (message?.text)! + " " + (message?.chatPartnerID())!
if let seconds = message?.timestamp?.doubleValue {
let timestampDate = Date(timeIntervalSince1970: seconds)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "hh:mm a"
timeLabel.text = dateFormatter.string(from: timestampDate)
}
//userImage.image = message?.
}
} }
图片下载扩展程序文件:
extension UIImageView {
func loadImageFromCacheWithUrlString( urlString: String) {
if urlString != "" {
self.image = nil
if let cachedImage = imageCache.object(forKey: urlString as AnyObject) {
self.image = cachedImage as? UIImage
self.contentMode = .scaleAspectFill
return
}
let url = URL(string : urlString )
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error!)
return
}
DispatchQueue.main.async(execute: {
if let downloadedImage = UIImage(data: data!) {
imageCache.setObject(downloadedImage, forKey: urlString as AnyObject)
self.image = downloadedImage
self.contentMode = .scaleAspectFill
}
})
}).resume()
}
}
}
答案 0 :(得分:4)
基本上,您使用单元重用,因此每次重新使用以前的单元格时,都会重复使用以前的单元格数据,因此您需要清除以前的数据。你应该nil图像查看下载新图像或使用占位符图像
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UserListTableViewCell
. cell.userImage.image = nil
let message = messages[indexPath.row]
cell.message = message
return cell
}
更新: From apple doc
如果UITableViewCell对象是可重用的 - 也就是说,它具有重用标识符 - 在从UITableView方法返回对象之前调用此方法 dequeueReusableCell(withIdentifier :) 。出于性能原因,您应该仅重置与内容无关的单元格属性,例如,alpha,编辑和选择状态。表格视图的代表 的tableView(_:cellForRowAt :) 重复使用单元格时应始终重置所有内容。如果单元对象没有关联的重用标识符,则不会调用此方法。如果重写此方法,则必须确保调用超类实现。
所以请放入UserListTableViewCell
班级
override func prepareForReuse() {
super.prepareForReuse()
self.userImage.image() = nil
// self.userImage.image = nil // above line not working then try this
}
答案 1 :(得分:3)
另一种解决方案
您可以使用UIImage(data: Data(contentsOf: URL(string: urlString)!))
从url检索图像,但它占用主线程,因此需要缓存。
此解决方案不会显示错误图像,但不会很好,因为初始化会导致延迟。
class URLImageRetriever {
fileprivate static var cache = NSCache<AnyObject,UIImage>()
static func getImage(from urlString: String) -> UIImage? {
var image = URLImageRetriever.cache.object(forKey: urlString as AnyObject)
if image == nil {
do {
try image = UIImage(data: Data(contentsOf: URL(string: urlString)!))
if let image = image {
URLImageRetriever.cache.setObject(image, forKey: urlString as AnyObject)
}
} catch {
}
}
return image
}
}
<强>来源强>
您的扩展程序loadImageFromCacheWithUrlString
可能不适合这种情况。
让我们讨论一下这种情况:
a
要求显示url-a
的图片。现在有一个URLSession task-a
正在运行。a
会请求显示url-b
的图像。现在有一个URLSession task-b
正在运行。task-b
从url-b
检索到的图片。您的ImageView a
现在可以完美显示url-b
的图片。tast-a
稍后的图片。您的ImageView设置为显示图像格式url-a
。让我们感到困惑。每当您检索图片时,都应该检查想要使用imageview显示的内容。
例如:
URLImageUtil.loadImageFromCacheWithUrlString(urlString: profileImageUrl, completion: {
url, image in
if self.message.profileImageUrl == url {
self.userImage.image = image
}
})
class URLImageUtil {
static func loadImageFromCacheWithUrlString(urlString: String, completion: @escaping (_ url: URL,_ image: UIImage)->Void) {
if let url = URL(string: urlString) {
URLSession.shared.dataTask(
with: url, completionHandler: {data,response,error in
if (data) != nil {
if let image = UIImage.init(data: data!) {
completion(url, image)
} else {
print("data not image from url: \(url)")
}
} else {
print("no data from url: \(url)")
}
})
} else {
print("error url: \(urlString)")
}
}
}
答案 2 :(得分:1)
你可以这样试试吗
var user = JSON.parse('{"firstname": "Mr.", "lastname": "My Father's Son"}');