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

我是iOS开发的初学者,我想制作一个instagram克隆应用程序,并且在制作instagram克隆应用程序的新闻时遇到问题。

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

但是当我运行应用程序时,我的故事板中的虚拟图像和标签与我在表格视图中放置的下载数据重叠。 我下载的数据将最终显示后,我向下滚动

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

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

有3个用户在.gif中显示

  1. 用户名(故事板中的虚拟人物)
  2. JokowiRI
  3. MegawatiRI

在从Firebaseasynchronous下载图像(在加载指示器被解除之后)之后,我预计MegawatiRI将显示在表格的顶部,但是虚拟将首先显示,但是在我向下滚动并返回到顶部之后,MegawatiRI将最终出现。

我相信MegawatiRI已经成功下载了,但我不知道为什么虚拟图像看起来与实际数据重叠。 我不想让我的应用程序运行时显示假人

这里是原型单元格的截图

在这里输入图像说明

这里是表视图控制器的简化代码:

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

这里是表格视图单元的简化代码:

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

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

提前致谢 :)

回答

出现虚拟图像的原因是您的表视图控制器在当前用户在tableViewController上正确设置之前开始绘制单元格。

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

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

之后,您重新加载数据,并且当前用户已经设置好了,所以事情就像预期的那样开始工作了。

这条线从你的updateUI()应该隐藏你的虚拟形象。 但是,updateUI并不总是如上所述被调用:

 self.mediaImageView.image = nil 

我真的不明白为什么updateUI需要当前用户不是零。 所以你可以在你的didSet观察器中消除零testing,并且总是调用updateUI:

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

或者,你可以重新排列你的表视图控制器,在加载数据源之前实际等待当前用户被设置。 viewWillAppear中与login相关的代码嵌套完成handers来设置当前用户。 这些可能是asynchronous执行的..所以你要么等待他们完成或处理当前用户为零。

 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)我认为这是一个很好的forms来重新加载单元格(使用reloadRows),当图像下载并已被插入到您的共享caching。 你可以参考这个问题的答案,看看从一个单元发起的asynchronous任务如何使用NotificationCenter或委托来联系tableViewController。

(2)我怀疑你的图像下载任务目前正在主线程中运行,这可能不是你想要的。 当你解决这个问题的时候,你需要切换回主线程来更新镜像(就像现在这样做)或者重新加载这个镜像(正如我上面推荐的那样)。

在主线程中更新你的UI。

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