Swift 3:tableView复制来自Firebase的加载图片
我正试图显示一个用户列表与图像。 这是代码
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文件中,我正在下载图像(也使用caching)并将其显示在表格中。 但是我看到一些行有重复/重复的图像。 在重新加载重复消失,但它的垂直滚动回来。
有时候是这样的 :
这是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() } }
}
基本上你使用单元复用,所以每次新的重用以前的单元,所以它是重用以前的单元格数据,所以你需要清除以前的数据。 您应该无图像查看下载新图像或使用占位符图像
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 }
更新: 从苹果文档
如果一个UITableViewCell对象是可重用的 – 也就是说,它有一个重用标识符 – 这个方法在从UITableView方法dequeueReusableCell(withIdentifier :)返回之前被调用。 出于性能原因,您应该只重置与内容无关的单元格的属性,例如,alpha,编辑和select状态。 tableView(_:cellForRowAt :)中的表视图委托应该在重用单元时总是重置所有的内容。 如果单元对象没有关联的重用标识符,则不调用此方法。 如果重写此方法,则必须确保调用超类实现。
所以把你的UserListTableViewCell
类
override func prepareForReuse() { super.prepareForReuse() self.userImage.image() = nil // self.userImage.image = nil // above line not working then try this }
另一个解决scheme
你可以使用UIImage(data: Data(contentsOf: URL(string: urlString)!))
从url中获取图像,但占用主线程,所以caching是必须的。 此解决scheme不会显示错误图像,但不好,因为初始化原因延迟。
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 { Designer.cache.setObject(image, forKey: urlString as AnyObject) } } catch { } } return image } }
起源
你的扩展loadImageFromCacheWithUrlString
可能不适合这种情况。
我们来讨论一下这种情况:
- 您的ImageView请求呈现
url-a
图像。 现在有一个URLSessiontask-a
正在运行。 - 你的UITableViewCell被重用来呈现另一个数据源,所以你的ImageView
a
要求呈现url-b
图像。 现在有一个URLSessiontask-b
正在运行。 -
task-b
-B从url-b
检索图片。 您的ImageView现在完全显示来自url-b
图像。 - 以后再拍一张照片。 您的ImageView被设置为显示图像forms的
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)") } } }
你可以试试这个方法吗?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UserListTableViewCell cell.userImage.image = UIImage(named: "blank-user") let message = messages[indexPath.row] cell.message = message return cell }
- 无法将types''的值转换为期望的参数types'String':在表视图单元格中添加数组以从Fireabse获取数据时
- 无法在Swift应用中导入Firebase
- 在iOS Obj-C中何处添加Firebase数据库引用
- 为什么removeAllObservers()不能在deinit中工作?
- 在Xcode中添加Firebase时如何解决“重复的符号”
- Firebase在Swift中检索数据
- iOS中使用新的Firebase消息传送SDK进行通知
- Firebase云消息传递是否支持VOIP pushkit服务?
- 发布到Clearcut时发生错误:(null),Google Cloud Speech API中的状态码为400