2016-05-30 99 views
0

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

我在哪里可以运行tableView.reloadData()以便我的tableView数据源更新并给出正确的可能posts?我试过把FeedController().tableView.reloadData()放在didSet中,我试过把它放在viewDidLoad()中,但这些都没有工作。我也尝试添加一个名为_posts的变量,并将其设置为posts,并将didSet与中的didSet相加,但这也不起作用。

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

     }) 
    } 
+0

你的问题是,你需要在屏幕上的视图控制器的上下文中执行'reloadData'; 'FeedController()。tableView.reloadData()'创建一个'FeedController'的新实例,这没有帮助。你可以得到你想要的一种方法是从'didSet'发布一个NSNotification,并让感兴趣的视图控制器订阅它。是的,全局变量是一个坏主意。创建一个单例类或创建一个实例并将其传递给您的每个视图控制器 – Paulw11

+0

您需要能够知道getAllPosts何时结束,然后才能调用reloadData。 getAllPosts如何看起来像? – Cristik

回答

0

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

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

  • 如果一个方法或属性都属于一个实例(也就是,它可以从实例的实例会发生变化)你self.propertyself.method()调用它,尽管通常你可以放弃self.,只要它不会造成歧义。

  • 如果一个方法或属性属于整个类(因此它被声明为static letstatic varstatic func),那么你将与NameOfTheClass.propertyNameOfTheClass.method()调用它。在你的情况下,你可以称它为FeedController.propertyFeedController.method()。即,没有尾随括号。在任何情况下,应该谨慎使用类方法和属性,并且在这种情况下可能不合适。

解决了这个问题后,我们有如何重新加载数据的问题。如果移动postsFeedController(使阵列的实例变量),并添加tableView.reloadData()(不self.)到postsdidSet(),你应该是不错的,尽管其他无关的代码味道,其他人都强调,你应该尝试修复,但这些不应该影响您重新加载数据的能力。

+0

谢谢你的信息。它确实有帮助。这里是rub,我的firebaseService类需要访问帖子,以便它可以从数据库中追加项目(参见更新后的代码)。从FirebaseService类访问帖子的最佳方式是什么? –

+0

我为这个类创建了一个新的静态常量并引用它。我假设这是正确的?与此同时,一切编译,但我仍然没有得到正确更新的部分。 didSet的帖子正在返回2的计数,但部分数量看起来并不像它正在更新。 –

+0

不需要。现在您将'FeedController'转换为单例。这是为了保持PG13,这是不明智的。单例是一种需要谨慎使用的模式,99%的时间适用于模型层的某些组件;几乎从不在VC层。 – catalandres

0

所以了蝙蝠:

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

这不是一个答案 –

+0

我告诉你,实例化另一个FeedController的部分将不起作用,它放在哪里不是答案? “我在哪里可以运行tableView.reloadData(),以便我的tableView数据源更新,并给我正确的帖子?” “何处放置重载调用将取决于您的要求,例如,如果您在来回UIViewController的地方出现大量的中断,并且其他UIViewController中的数据正在更改,则可以在重载中重新加载viewWillAppear()或其他生命周期方法。“ – Jay

+0

我已经说过,在我的帖子中,我试过了,并没有工作。就你说的放哪里来说,你有一个与此无关的例子。对于这个问题,我并没有使用segues甚至IB。 –