ios - 界面生成器中的图像和标签与 TableView 单元格中的数据重叠

标签 ios swift firebase

我是iOS开发初学者,想做一个instagram clone app,在制作instagram clone app的news feed时遇到了问题。

所以我使用 Firebase 来存储图像和数据库。发布图片(将数据上传到 Firebase)后,我想使用从我的 Firebase 上传的数据填充表格 View 。

但是当我运行该应用程序时, Storyboard中的虚拟图像和标签与我放入表格 View 中的下载数据重叠。我下载的数据最终会在我向下滚动后显示。

这是我运行应用程序时的 gif:

http://g.recordit.co/iGIybD9Pur.gif

.gif 中显示了 3 个用户

  1. 用户名( Storyboard中的虚拟人)
  2. 佐科维里
  3. 梅加瓦蒂研究所

从 Firebase 异步下载图像后(加载指示器消失后),我希望 MegawatiRI 会显示在表格顶部,但虚拟图像会先显示,但在我向下滚动并返回顶部后, MegawatiRI 最终会出现。

我相信 MegawatiRI 已成功下载,但我不知道为什么虚拟图像似乎与实际数据重叠。我不希望在我的应用程序运行时显示虚拟对象。

这是原型(prototype)单元格的屏幕截图:

enter image description here

下面是 TableView Controller 的简化代码:

class NewsFeedTableViewController: UITableViewController {


    var currentUser : User!
    var media = [Media]()



    override func viewDidLoad() {
        super.viewDidLoad()



        tabBarController?.delegate = self


        // to set the dynamic height of table view
        tableView.estimatedRowHeight = StoryBoard.mediaCellDefaultHeight
        tableView.rowHeight = UITableViewAutomaticDimension

        // to erase the separator in the table view
        tableView.separatorColor = UIColor.clear

    }


    override func viewWillAppear(_ animated: Bool) {

        // check wheter the user has already logged in or not

        Auth.auth().addStateDidChangeListener { (auth, user) in

            if let user = user {

                RealTimeDatabaseReference.users(uid: user.uid).reference().observeSingleEvent(of: .value, with: { (snapshot) in

                    if let userDict = snapshot.value as? [String:Any] {
                        self.currentUser = User(dictionary: userDict)
                    }


                })

            } else {
                // user not logged in
                self.performSegue(withIdentifier: StoryBoard.showWelcomeScreen, sender: nil)
            }


        }

        tableView.reloadData()
        fetchMedia()



    }




    func fetchMedia() {

    SVProgressHUD.show()

    Media.observeNewMedia { (mediaData) in


        if !self.media.contains(mediaData) {
            self.media.insert(mediaData, at: 0)
            self.tableView.reloadData()
            SVProgressHUD.dismiss()
        }


        }

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: StoryBoard.mediaCell, for: indexPath) as! MediaTableViewCell


        cell.currentUser = currentUser
        cell.media = media[indexPath.section]



        // to remove table view highlight style
        cell.selectionStyle = .none



        return cell
    }


    }

下面是表格 View 单元格的简化代码:

class MediaTableViewCell: UITableViewCell {

    var currentUser: User!
    var media: Media! {
        didSet {

            if currentUser != nil {
                updateUI()
            }

        }
    }

    var cache = SAMCache.shared()



    func updateUI () {


        // check, if the image has already been downloaded and cached then just used the image, otherwise download from firebase storage


        self.mediaImageView.image = nil
        let cacheKey = "\(self.media.mediaUID))-postImage"

        if let image = cache?.object(forKey: cacheKey) as? UIImage {
            mediaImageView.image = image
        } else {
            media.downloadMediaImage { [weak self] (image, error) in

                if error != nil {
                    print(error!)
                }


                if let image = image {
                    self?.mediaImageView.image = image
                    self?.cache?.setObject(image, forKey: cacheKey)

                }


            }

        }

那么是什么让虚拟图像与我下载的数据重叠?

最佳答案

回答

出现虚拟图像是因为您的 TableView Controller 在您的当前用户在 tableViewController 上正确设置之前开始渲染单元格。

因此,在第一次调用 cellForRowAtIndexPath 时,您的 Controller 中可能有一个 nil currentUser,它被传递给单元格。因此,您的单元格类中的 didSet 属性观察器不会调用 updateUI():

didSet {
        if currentUser != nil {
            updateUI()
        }
    }

稍后,您重新加载数据并且当前用户已经设置,所以事情开始按预期工作。

updateUI() 中的这一行应该隐藏您的虚拟图像。但是,updateUI 并不总是像上面解释的那样被调用:

self.mediaImageView.image = nil

我真的不明白 updateUI 需要当前用户不是 nil 的原因。所以你可以在你的 didSet 观察者中消除 nil 测试,并且总是调用 updateUI:

var media: Media! {
    didSet {
        updateUI()
    }

或者,您可以重新安排您的 TableView Controller ,以便在加载数据源之前真正等待当前用户被设置。 viewWillAppear 中与登录相关的代码具有嵌套的完成处理程序来设置当前用户。这些可能是异步执行的..所以你要么必须等待它们完成,要么处理当前用户为零的情况。

Auth.auth etc { 
   // completes asynchronously, setting currentUser 
}
// Unless you do something to wait, the rest starts IMMEDIATELY
// currentUser is not set yet

tableView.reloadData()
fetchMedia()

其他说明

(1) 我认为当图像下载并插入共享缓存时重新加载单元格(使用 reloadRows)是一种很好的形式。可以引用这个question里面的答案查看从单元启动的异步任务如何使用 NotificationCenter 或委托(delegate)联系 tableViewController。

(2) 我怀疑您的图片下载任务目前正在主线程中运行,这可能不是您想要的。当您修复该问题时,您需要切换回主线程以更新图像(正如您现在所做的那样)或重新加载该行(正如我在上面所建议的那样)。

关于ios - 界面生成器中的图像和标签与 TableView 单元格中的数据重叠,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46930379/

相关文章:

c++ - 如何为使用 AKOscillatorBank 演奏的每个音符设置随机相位?

firebase - 获取 firestore 数据库时 "itemCount: snapshot.data.documents.length"不再工作。有谁知道如何解决这个问题?

javascript - React Native - 无法获取数组中的项目,或无法在列表中显示数组中的项目

ios - 如何使用 swift 创建一个闹钟应用程序?

ios - 应用程序未运行时,Objective-C IOS 7 推送通知保存数据?

ios - 如何以编程方式从 UITableViewController 顺利过渡到 UIViewController

ios - Swift:展开导致swift编译缓慢

android - 从客户端发送 firebase 云消息而不暴露 API secret

ios - 分组图像过滤器和链接图像过滤器之间的区别

ios - 用 JWPlayer 通知替换 MPMoviePlayer 通知