在 ViewWillAppear 完成运行之前调用 CellForRowAtIndexPath

Posted

技术标签:

【中文标题】在 ViewWillAppear 完成运行之前调用 CellForRowAtIndexPath【英文标题】:CellForRowAtIndexPath called before ViewWillAppear finished running 【发布时间】:2016-01-24 07:25:00 【问题描述】:

我有一个从 Parse 数据库中提取信息并将其显示在 UITableView 中的应用程序。我从 viewWillAppear 函数中的解析中提取信息,并将其显示在 tableView(cellForRowAtIndexPath) 函数中。有时我收到一个错误,因为存储 Parse 信息的数组的长度为 0,我尝试访问数组边界之外的索引处的信息。我相信这是因为在 viewWillAppear 完成运行之前调用了 cellForRowAtIndexPath。这是可能的还是我的错误肯定来自其他地方?

编辑:错误不会每次都发生,我找不到重现它的方法

override func viewWillAppear(animated: Bool) 

    //begin ignoring events until the information is finished being pulled
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()

    resultsArray.removeAll(keepCapacity: false)

    //run query
    let query = PFQuery(className: "Answers")
    query.findObjectsInBackgroundWithBlock  (objects, error) -> Void in

        if let objects = objects 

                    //append information to the resultsArray 
                
            
            self.tableView.reloadData()
        
    
    //information is now pulled, so allow interaction 
   UIApplication.sharedApplication().endIgnoringInteractionEvents()




override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! answerCell

    // THIS IS WHERE THE ERROR OCCURS
    resultsArray[indexPath.row].imageFile.getDataInBackgroundWithBlock  (data, error) -> Void in

        //set image within cell
    
    return cell

【问题讨论】:

从你身边放一些代码 请看代码@Graham 请在cellForRowAtIndexPath 中设置一个断点,然后运行并逐步查看发生了什么。然后你可以同时看到你的 arry 是否为空。 你能显示numberOfRowsInSection的代码吗? numberOfRowsInSection 返回 resultsArray.count @Paulw11 【参考方案1】:

我建议您将 Parse 中的数据加载到一个临时数组中,然后在调用 reloadData 之前将其分配给您的属性数组 - 这将避免任何潜在的竞争条件并消除对 removeAll 的需要可能是您问题的很大一部分;

override func viewWillAppear(animated: Bool) 

    //begin ignoring events until the information is finished being pulled
    UIApplication.sharedApplication().beginIgnoringInteractionEvents()



    //run query
    let query = PFQuery(className: "Answers")
    query.findObjectsInBackgroundWithBlock  (objects, error) -> Void in

        var localArray=[SomeType]()

        if let objects = objects 

                    //append information to the localArray 
                
            
            self.resultsArray=localArray
            self.tableView.reloadData()
        
    
    //information is now pulled, so allow interaction 
   UIApplication.sharedApplication().endIgnoringInteractionEvents()


【讨论】:

奇怪的是,这解决了问题。我想知道为什么会这样……但还是谢谢你! 数组不是线程安全的,所以任何时候你从一个线程更新并从另一个线程读取你都会遇到问题 @rohaldb,如果你看看我的回答,你会发现“实际发生了什么”(进一步@Paulw11 的评论)。【参考方案2】:

看起来在viewWillAppear 中你有一个后台块findObjectsInBackgroundWithBlock 有一些工作要做在不同的线程(AKA 离开主线程),这意味着 viewWillAppear 将完成而块将得到回调。

这解释了为什么在 viewWillAppear 完成后调用 cellForRowAtIndexPath,因为回调块。

这意味着一切都很好,viewWillAppear 实际上确实完成了一次合法的“运行”。

您实际上可以在回调方法中(在viewWillAppear)中放置一个断点,在cellForRowAtIndexPath 中放置一个断点,然后查看在调用cellForRowAtIndexPath 时回调何时发生。

如果您需要与 Parse 不同的方法,也许您应该查看他们的 documentation。

【讨论】:

【参考方案3】:

实际上,如果您的回调无法访问self.tableView,那么一切都会照常进行。你可以试一试。

当我在init 方法viewDidLoadinit 结束之前调用的方法中访问屏幕上的视图时发生了这种情况。

不管怎样,你应该知道这个事实。并且您在需要cellForRowAtIndexPath 的回调中访问您的tableView(在viewWillAppear 完成之前调用)。

【讨论】:

我不太确定你的意思/如何解决它。 “实际上,如果您的回调无法访问 self.tableView”是什么意思? 你可以评论self.tableView.reloadData()然后看看会发生什么。 但是信息不会显示在表格中? 你可以用log来判断它们的关系。

以上是关于在 ViewWillAppear 完成运行之前调用 CellForRowAtIndexPath的主要内容,如果未能解决你的问题,请参考以下文章

navigationController popToRootViewControllerAnimated:YES 不调用 viewWillAppear

如何使用情节提要 iOS7 调用 viewWillAppear

空的初始视图控制器,未调用 viewWillAppear() 和 viewDidAppear()

如何在自定义导航中添加 viewwillappear 和 viewdidappear 之间的延迟?

在 UITableViewController 中没有调用 viewWillAppear?

如果在“viewWillAppear”或“viewDidLoad”方法中完成,视图不会调整大小