我有一个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)
}
}
}
答案 0 :(得分:0)
在从服务器接收数据后,您实际运行了self.tableView.reloadData()
吗?乍一看,似乎首先调用reloadData()然后你的完成块更新你的本地数据。
如果是这样的话,那么你的数组肯定与你的表数据源不同步。
答案 1 :(得分:0)
看起来您在此请求的reloadData
部分得到奇怪结果的原因是您在后台队列上调用了reloadData
,这将使其成为现实在一个不可预测的时间。要解决这个问题,你可以将这部分调用放回主队列,如下所示:
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in
self.tableView.reloadData()
]
这应该至少可以解决你认为应该在表重新加载几秒后遇到的问题。不过,我不得不说,我不完全理解为什么在第一次函数调用后强制用户注销并重新登录。我也认为你可能有两个异步调用发生的潜在问题,它们都修改了同一个属性self.bookListing
。您可能需要考虑将第二个查询放入一个单独的函数中,并在第一个函数完成时调用它。这样,您就可以保证第一个查询在第二个查询完成之前完成。
最后,与tableView.reloadData()
问题类似,您在后台队列中提出UIAlertController
时遇到同样的问题。