【问题标题】:Having trouble reloading tableView重新加载 tableView 时遇到问题
【发布时间】:2016-05-30 22:11:35
【问题描述】:

我在重新加载 tableView 时遇到问题。当我的firebaseService.getAllPosts() 方法运行时,它会给我数据库中的两个帖子(如预期的那样)。我可以这么说,因为当didSet 打印运行时,它给了我正确的计数。但是,因为我知道在方法运行之前设置了 tableview,所以我知道我需要重新加载 tableview 以更新数据源中的计数。问题就在于此。我故意将posts 变量放在我的班级之外,以便可以从每个班级访问它。 (如果这不是一个好的做法,请告诉我。)

我在哪里可以运行 tableView.reloadData() 以便我的 tableView 数据源更新并为我提供 posts 的正确功能?我尝试将FeedController().tableView.reloadData() 放入didSet 并尝试将其放入viewDidLoad(),但这些都不起作用。我还尝试添加一个名为_posts 的变量并将其设置为等于posts,然后在didSet 中添加didSettableView.reloadData(),但这也不起作用。

class FeedController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    let tableView = UITableView(frame: UIScreen.mainScreen().bounds, style: UITableViewStyle.Plain)
    let cellId = "PhotoCell"
    let textCellId = "TextCell"
    let firebaseService = FirebaseService.sharedInstance
    static let sharedFeedInstance = FeedController()
    var posts = [Post]() {
     didSet {
      tableView.reloadData()
      print(posts.count)
      }
  }



    override func viewDidLoad() {
        super.viewDidLoad()

        firebaseService.getAllPosts()

        tableView.dataSource = self
        tableView.delegate = self
        self.view.addSubview(tableView)

    }

    // MARK: - Table view data source

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        print("sections: \(posts.count)")
        return posts.count
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 1
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let post:Post? = posts[indexPath.section]


        if let _ = post?.imageContentName {
            let photoFeedCell = tableView.dequeueReusableCellWithIdentifier(self.cellId, forIndexPath: indexPath) as? FeedTVCellWithPhoto
            photoFeedCell?.post = post
            return photoFeedCell!
        }

        let textFeedCell = tableView.dequeueReusableCellWithIdentifier(self.textCellId, forIndexPath: indexPath) as? FeedTVCellText
        textFeedCell?.post = post
        return textFeedCell!
    }
}

更新 1:FirebaseService 类中的 getAllPosts 方法

    func getAllPosts() {
        let postRef = ref.child("posts")
        postRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
//            print(snapshot.value)
            if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
                for snap in snapshots {
                    if let postDictionary = snap.value as? Dictionary<String, AnyObject> {
                        let key = snap.key
                        let post = Post(key: key, dictionary: postDictionary)
                        FeedController.sharedFeedInstance.posts.insert(post, atIndex: 0)
                    }
                }
            }

        })
    }

【问题讨论】:

  • 您的问题是您需要在屏幕上的视图控制器的上下文中执行reloadDataFeedController().tableView.reloadData() 创建FeedController 的新实例,但没有帮助。获得所需内容的一种方法是从 didSet 发布 NSNotification 并让感兴趣的视图控制器订阅它。是的,全局变量是个坏主意。创建一个单例类或创建一个实例并将其传递给您的每个视图控制器
  • 您需要知道getAllPosts 何时结束,然后才能调用reloadDatagetAllPosts 长什么样子?

标签: ios swift uitableview


【解决方案1】:

本质上,您正在以错误的方式处理FeedController 的方法和属性。每次您在代码中使用FeedController() 时,您都应该使用self

以下两段是关于类和实例方法和属性的复习。如果它已经在你的雷达中,请随意忽略它们:

    1234563因为它不会产生歧义。
  • 如果一个方法或属性属于整个类(因此它被声明为static letstatic varstatic func),那么您可以使用NameOfTheClass.propertyNameOfTheClass.method() 调用它。在您的情况下,您可以将其称为FeedController.propertyFeedController.method()。也就是说,不带尾括号。在任何情况下,类方法和属性都应该谨慎使用,在这种情况下可能不合适。

解决了这个问题,我们就有了如何重新加载数据的问题。如果您将posts 移动到FeedController 内(使数组成为实例变量)并将tableView.reloadData()(没有self.)添加到postsdidSet(),您应该很好,尽管有其他不相关的代码气味其他人已经突出显示并且您应该尝试修复,但这些不应该影响您重新加载数据的能力。

【讨论】:

  • 感谢您提供的信息。这真的很有帮助。这是问题所在,我的 firebaseService 类需要访问帖子,以便它可以从数据库中将项目附加到它(请参阅更新的代码)。从 FirebaseService 类访问帖子的最佳方式是什么?
  • 我为类创建了一个新的静态常量并引用了它。我假设这是正确的?有了这个,一切都编译了,但我仍然没有让这些部分正确更新。帖子的 didSet 返回计数为 2,但部分计数看起来并未更新。
  • 没有。现在你正在把FeedController 变成一个单例。为了保持 PG13,这是不明智的。单例是一种需要谨慎使用的模式,99% 的时间它适用于模型层的某些组件;几乎从不在 VC 层中。
  • getAllPosts() 的目的是将数据库连接到posts 的数组。你可以把它变成tieDatabasePostsTo(feedController: FeedController),而不是调用FeedController.sharedFeedInstance.posts.insert(post, atIndex: 0),而是调用feedController.posts.insert(post, atIndex: 0)。然后viewDidLoad() 内部的调用变为tieDatabasePostsTo(self)。这有意义吗?
  • 在某种程度上,您传递了该引用,以便FirebaseService 可以与您交谈。它类似于委托模式。
【解决方案2】:

所以就这样吧:

  • “FeedController().tableView.reloadData()”是 实例化另一个 FeedController。那是行不通的。将 reload 调用放在哪里取决于您的要求。例如,如果您在来回切换到此 UIViewController 时发生很多转场,并且其他 UIViewController 中的数据正在更改,则可以在 viewWillAppear() 或其他生命周期方法的覆盖中重新加载。您需要在 tableView 上为加载到 UIWindow 中的 UIViewController 实例调用它,而不是您现在正在做的事情。
  • 您以编程方式执行大量此类工作的任何原因 而不是通过故事板?无论哪种方式都很好,但我找到了故事板 是一个很好的分离。例如,如果您通过故事板使用 UITableViewController,您可以让它设置委托和数据源,而无需通过看起来像丑陋样板的代码来完成。只要您符合协议,您也可以在不使用 UITableViewController 的情况下设置这些。那些在storyboard里可以处理的东西应该是我平时常去的。
  • 您的类正在扩展 UIViewController 并实现这两个协议,为什么不直接扩展 UITableViewController?除非您手动将 UITableView 放在那里并且需要在该 UIViewController 上显示 UITableView 以外的其他内容,否则我没有理由想到做您正在做的事情。
  • 还有一点需要注意的是,您执行 PhotoFeedCell 和 TextFeedCell 的方式有点奇怪,并且会发出混合信号。您将一个可重用的单元格出列并进行可选的强制转换,然后使用可选的链接,这两者都意味着您接受它可能为 nil,但随后强制解开它。

【讨论】:

  • 这不是答案
  • 我告诉你实例化另一个 FeedController 不起作用的部分以及将它放在哪里,不是答案吗? “我在哪里可以运行 tableView.reloadData() 以便我的 tableView 数据源更新并为我提供正确的帖子?” “将重新加载调用放在哪里取决于您的要求。例如,如果您在此 UIViewController 来回切换时发生了很多转折,并且其他 UIViewController 中的数据正在更改,您可以在 viewWillAppear 的覆盖中重新加载() 或其他生命周期方法。”
  • 我已经在我的帖子中说过,我尝试过但没有成功。至于你说把它放在哪里,你有一个与此无关的例子。我没有使用 segues 甚至 IB 来解决这个问题。
  • @Jay:您正在尝试解决问题并同时提供代码批评。它没有提供有关导致 OP 问题的原因的信息。
猜你喜欢
  • 2013-07-30
  • 1970-01-01
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 2017-12-19
相关资源
最近更新 更多