【问题标题】:Swift 3 : tableView duplicating loaded images from FirebaseSwift 3:tableView 复制从 Firebase 加载的图像
【发布时间】:2017-07-24 15:37:08
【问题描述】:

我正在尝试显示带有图像的用户列表。这是代码

    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()
    }


}

}

【问题讨论】:

  • 你为cell.message调用的代码写了什么?
  • 重用cell set nil image view
  • 在 UserListTableViewCell 中分享您的图像查看代码
  • @Larme:分享代码。
  • @NazmulHasan:你现在可以看看了吗?

标签: ios swift uitableview firebase


【解决方案1】:

基本上你使用单元格重用,所以每次新的重用以前的单元格,所以它重用以前的单元格数据,所以你需要清除以前的数据。您应该 nil images 查看下载新图像或使用占位符图像

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 
}

【讨论】:

  • 你会试试这条线cell.userImage.image = UIImage(named: "")
  • 仍然没有运气
  • 这里有另外 2 个回答,那是怎么回事
  • @snowwalker 你确定你的图片在 firebase 数据库或图片 url 上不一样
  • @snowwalker 请userImage 将子视图添加到cellcontentView 属性。添加子视图时,您负责定位这些视图并自行设置其内容。
【解决方案2】:

另一种解决方案

你可以使用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 可能不适合这种情况。

让我们讨论一下这种情况:

  1. 您的 ImageView a 请求显示 url-a 的图像。现在有一个 URLSession task-a 正在运行。
  2. 您的 UITableViewCell 被重用于呈现另一个数据源,因此您的 ImageView a 请求呈现 url-b 的图像。现在有一个 URLSession task-b 正在运行。
  3. task-burl-b 检索到的图片。您的 ImageView a 现在可以完美地显示来自 url-b 的图像。
  4. 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)")
        }
    }
}

【讨论】:

  • 我可以使用 .resume() 运行代码,但仍然遇到图像重复问题。
  • 感谢您的帮助。我试过了,但是太慢了。关于做同样事情的不同方式的任何其他建议?
【解决方案3】:

你可以这样试试吗

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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多