【问题标题】:Issue trying to complete Firebase Storage download before showing tableview在显示 tableview 之前尝试完成 Firebase Storage 下载的问题
【发布时间】:2018-03-10 22:20:36
【问题描述】:

我有一个表格视图,它会根据单元类从 Firebase 下载图像。我注意到在使用该应用程序时,具有相同单元格标识符的单元格将在显示新图像之前显示之前下载的图像。这是我改之前的样子。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if tableData[indexPath.row]["Image"] != nil {
        let cell = tableView.dequeueReusableCell(withIdentifier: "imageNotesData", for: indexPath) as! ImageNotesCell
        cell.notes.delegate = self
        cell.notes.tag = indexPath.row
        cell.notes.text = tableData[indexPath.row]["Notes"] as! String
        guard let imageFirebasePath = tableData[indexPath.row]["Image"] else {
            return cell }
        let pathReference = Storage.storage().reference(withPath: imageFirebasePath as! String)
        pathReference.getData(maxSize: 1 * 1614 * 1614) { data, error in
            if let error = error {
                print(error)
            } else {
                let image = UIImage(data: data!)
                cell.storedImage.image = image
            }
        }
        return cell
    }
    else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "notesData", for: indexPath) as! NotesCell
        //let noteString = tableData[indexPath.row]["Notes"] as! String
        cell.notes.text = tableData[indexPath.row]["Notes"] as! String
        cell.notes.delegate = self
        cell.notes.tag = indexPath.row
        return cell
    }
}

知道这不是一个好的用户体验并且看起来很笨重,我尝试将pathReference.getData 移动到我设置数据的位置,但视图会在我的图像完成下载之前出现。我尝试使用完成处理程序,但我仍然遇到问题。

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(true)
            getSectionData(userID: userID, city: selectedCity, completion: {(sectionString) in
            self.setupTableCellView(userID: userID, city: selectedCity, section: sectionString) { (tableData) in
                DispatchQueue.main.async(execute:  {
                    self.cityName?.text = selectedCity
                    self.changeSections.setTitle(sectionString, for: .normal)
                    self.currentSectionString = sectionString
                    self.setupTableData(tableDataHolder: tableData)
                })
            }
        })
}

func setupTableCellView(userID: String, city: String, section: String, completion: @escaping ([[String:Any]]) -> () ) {
        let databaseRef = Database.database().reference().child("Users").child(userID).child("Cities").child(city).child(section)
        var indexData = [String:Any]()
        var indexDataArray = [[String:Any]]()
        databaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
            for dataSet in snapshot.children {
                let snap = dataSet as! DataSnapshot
                //let k = snap.key
                let v = snap.value
                indexData = [:]
                for (key, value) in v as! [String: Any] {
                    //indexData[key] = value
                    if key == "Image" {
                        //let pathReference = Storage.storage().reference(withPath: value as! String)
                        print("before getImageData call")
                        self.getImageData(pathRef: value as! String, completion: {(someData) in
                            print("before assigning indexData[key]")
                            indexData[key] = someData
                            print("after assigning indexData[key]")
                        })
                    } else {
                        indexData[key] = value
                    }
                }
                indexDataArray.append(indexData)
            }
            completion(indexDataArray)
        })
    }

func getImageData(pathRef: String, completion: @escaping(UIImage) -> ()) {
    let pathReference = Storage.storage().reference(withPath: pathRef as! String)
    pathReference.getData(maxSize: 1 * 1614 * 1614, completion: { (data, error) in
        if let error = error {
            print(error)
        } else {
            let image = UIImage(data:data!)
            print("called before completion handler w/ image")
            completion(image!)
        }
    })
}

我不知道我是否以正确的方式接近这一点,但我想我是。我也猜想getData 调用是异步的,这就是为什么它总是会在显示表格视图后下载。

【问题讨论】:

  • Firebase API 在等待来自服务器的数据时都是异步的。 medium.com/google-developers/…
  • 所以我猜我必须在视图加载之前设置我的数据。
  • 非常不幸 - 这完全是完全错误的:/ OCC 很难.. 当您使用 Facebook 时,现代“应用程​​序”(即设备-云系统)看起来真的很容易。但是,看看 Facebook 有多少 IOS 程序员。

标签: ios swift firebase firebase-storage


【解决方案1】:

你不能这样做。

从 Firebase 发出请求。

随着时间的推移,你会收到很多回复——所有的信息和所有变化的信息。

当每个新项目到达时 - 不要忘记它可能是添加或删除 - 更改您的表格以显示所有当前项目。

那是 OCC!

OCC 是“偶尔连接的计算”。类似的短语是“离线优先计算”。因此,无论您何时使用您每天使用的任何主要服务,例如 Facebook、Snapchat 等,即“OCC”:无论您是否有带宽,一切都会保持正确同步。你知道?当前主要的端云计算范式。

【讨论】:

  • 感谢您的回答!你能解释一下什么是OCC吗?我不熟悉这个词
【解决方案2】:

编辑 - 查看 Fattie 关于 prepareForReuse() 的 cmets!

对于可重复使用的表格单元格,单元格首先将具有默认情况下 / 在 xib 上的外观。一旦他们被“使用”,他们就会拥有他们设置的任何数据。这可能会导致一些不稳定的行为。我发现了一个问题,在我的数据中的“默认”情况下,我没有做任何事情,因为它已经与 xib 匹配,但是如果数据的属性不同,我更新了外观。结果就是上下滚动真的很快,一些本来应该有默认外观的东西却变了外观。

不显示上一张图片的一个基本解决方案是显示一个占位符/空图片,然后调用您的图片的异步获取。不完全是您想要的,因为单元格仍会显示为空...

确保您有图片的本地存储,否则您将在向上和向下滚动时向服务器请求您已经拥有的图片!

我建议在你的 viewDidLoad 中调用一个方法来一次获取所有图像,然后,一旦你拥有了所有图像,在你的成功处理程序中调用 self.tableview.reloadData() 来显示所有图像。

【讨论】:

  • “这可能会导致一些不正常的行为。” 除非你的编程不可靠,Jake!您正在寻找的是 prepareForReuse() 。这是对表格视图进行编程时最基本的事情。给自己买一夸脱的便宜威士忌,坐下来整理一下。享受吧!
  • 嘿,嘘,如果你不知道自己在做什么,我的意思是很奇怪,请按照你在互联网上找到的随机教程来教你如何做这些事情!不过,谢谢你的提示!可悲的是,这对我来说是一本新书……我真的需要购买一本最新的 iOS 最佳实践书或其他东西……Ray Wenderlich 很棒,但并不全面……我仍然遇到并重构旧代码一切都在视图控制器中哈哈
  • 雷是个白痴。太绝望了,不值一提。你必须prepareForReuse()老伙伴。关于图像,它根本不像那样工作。你必须使用缓存解决方案(目前,我喜欢 Haneke - 有各种各样的...... DLImageLoader 传统上是最好的。你>必须cell
  • 一个让你前进的帖子...... stackoverflow.com/a/26355057/294884 不幸的是,某个醉汉的帖子已经很老了,所以没用。但它会让你指出。好机会
猜你喜欢
  • 2018-10-23
  • 2021-07-07
  • 1970-01-01
  • 2021-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-08
  • 1970-01-01
相关资源
最近更新 更多