从Parse Array中删除项目后UITableView崩溃

时间:2016-02-23 00:11:15

标签: ios uitableview parse-platform pfquery viewdidappear

我有一个iOS应用程序,它使用Parse作为它的后端。我有一个“User”类,它有一个数组“myBooks”,其中包含指向“Books”类中对象的指针。

我有两个显示所有用户书籍的视图控制器(vc1,vc2)。 Vc1根据createdAt以降序加载每个用户的书籍。 Vc2特定于PFUser.currentUser,因此它是仅存在的每个用户的书籍列表(即,vc1共有30本书,vc2有8本来自当前用户的书籍已登录)。

手头的问题: 我已经实现了一个刷卡到删除功能,用户可以从数据库中删除他们的书籍并且成功完成。新的图书数组将更新并保存到当前用户的数据库中,删除的图书不再存在。当我回到vc1(我正在使用标签栏控制器)时,我有一个viewDidAppear函数试图从数据库重新加载数据并重新加载tableview。不幸的是,当向下滚动tableview时,应用程序总是崩溃并出现越界错误。但是,我在vc1中有一个刷新按钮,如果我在返回vc1后按1-2次,则会避免崩溃。

如何让bookArray从最初的返回到vc1实际加载和更新tableview?

viewDidAppear函数:

override func viewDidAppear(animated: Bool) {

    if PFUser.currentUser() == nil{

        self.loginVC = self.storyboard!.instantiateViewControllerWithIdentifier("login") as! LoginViewController
        self.presentViewController(self.loginVC, animated: true, completion: nil)

    }


    else{
        PFUser.currentUser()!.fetchInBackgroundWithBlock({ (object, error) -> Void in
            if error == nil{
                //do nothing
            }
            else{
                let errorCode = error!.code
                switch errorCode{
                case 209:
                    PFUser.logOut()
                    self.loginVC = self.storyboard!.instantiateViewControllerWithIdentifier("login") as! LoginViewController
                    self.presentViewController(self.loginVC, animated: true, completion: nil)
                default:
                    break
                }

            }
        })
    }
    self.loadData()

}

loadData函数:

func loadData(){
        bookListing.removeAll()


        let checkForNewBookData:PFQuery = PFQuery(className: "Book")
        checkForNewBookData.orderByDescending("createdAt")


        checkForNewBookData.findObjectsInBackground().continueWithSuccessBlock({ //sets up local data store correctly
            (task: BFTask!) -> AnyObject! in
            return PFObject.unpinAllObjectsInBackgroundWithName("LocalBooks").continueWithSuccessBlock({
                (ignored: BFTask!) -> AnyObject! in

                // Cache new results
                let books = task.result as! [PFObject]
                self.bookListing.removeAll()
                self.bookListing = books
                let userDefaults = NSUserDefaults.standardUserDefaults()
                userDefaults.setObject("true", forKey: "localData")
                return PFObject.pinAllInBackground(books as [PFObject], withName: "LocalCabs")
            })
        })


        let getBookData = PFQuery(className: "Book")
        getBookData.orderByDescending("createdAt")
        getBookData.fromLocalDatastore()

        getBookData.findObjectsInBackgroundWithBlock { (objects : [PFObject]?, error : NSError?) -> Void in
            if error == nil{
                if let objects = objects{
                    for object in objects{
                        self.bookListing.append(object)
                    }
                    self.tableView.reloadData()
                }
            }
            else{
                let alert = UIAlertController(title: "Oops!", message: "Something went wrong. Try again.", preferredStyle: UIAlertControllerStyle.Alert)
                alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
                self.presentViewController(alert, animated: true, completion: nil)
            }
        }

    }

2 个答案:

答案 0 :(得分:0)

在从服务器接收数据后,您实际运行了self.tableView.reloadData() 吗?乍一看,似乎首先调用reloadData()然后你的完成块更新你的本地数据。

如果是这样的话,那么你的数组肯定与你的表数据源不同步。

答案 1 :(得分:0)

看起来您在此请求的reloadData部分得到奇怪结果的原因是您在后台队列上调用了reloadData,这将使其成为现实在一个不可预测的时间。要解决这个问题,你可以将这部分调用放回主队列,如下所示:

NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in
        self.tableView.reloadData()
    ]

这应该至少可以解决你认为应该在表重新加载几秒后遇到的问题。不过,我不得不说,我不完全理解为什么在第一次函数调用后强制用户注销并重新登录。我也认为你可能有两个异步调用发生的潜在问题,它们都修改了同一个属性self.bookListing。您可能需要考虑将第二个查询放入一个单独的函数中,并在第一个函数完成时调用它。这样,您就可以保证第一个查询在第二个查询完成之前完成。

最后,与tableView.reloadData()问题类似,您在后台队列中提出UIAlertController时遇到同样的问题。