我正在制作iOS 6程序,该程序从网站下载JSON数据并将其显示在表格视图中。我添加了一个刷新方法,巫婆工作得很好。我可以进入设置视图控制器(secondViewController)并更改地址,一切正常。然后,我使用pull to refresh方法并重新加载tableView。但如果我在更改地址后重新加载3次,我的应用程序崩溃了。我收到这个错误:
*** Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayM objectAtIndex:]: index 10 beyond bounds for empty array'
*** First throw call stack:
(0x1ca1012 0x10dee7e 0x1c430b4 0x3084 0xdd8fb 0xdd9cf 0xc61bb 0xd6b4b 0x732dd 0x10f26b0 0x229dfc0 0x229233c 0x2292150 0x22100bc 0x2211227 0x22bb333 0x22bb75f 0x1c60376 0x1c5fe06 0x1c47a82 0x1c46f44 0x1c46e1b 0x1bfb7e3 0x1bfb668 0x22ffc 0x1fbd 0x1ee5)
libc++abi.dylib: terminate called throwing an exception
我做错了什么?我该如何解决这个问题?谢谢你的帮助!
答案 0 :(得分:0)
跳出的关键设计考虑因素是您的retreiveData
方法明确地异步更新模型(citiesArray
),这意味着在发生这种情况时与tableview的任何交互都可能失败。您永远不应异步更新实际的citiesArray
本身。对该阵列的更新应该在主队列中进行。
您应该将retrieveData
更改为不接触现有的citiesArray
,而是创建并返回一个新数组,然后在您发送回主队列的代码中,只替换现有的citiesArray
并致电reloadData
,例如:
- (void)refresh:(UIRefreshControl *)refreshControl {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *newCitiesArray = [self retreiveData];
dispatch_async(dispatch_get_main_queue(), ^{
if (newCitiesArray) {
// you presumably only want to reload the data if `retrieveData` was successful
citiesArray = newCitiesArray
[myTableView reloadData];
}
[refreshControl endRefreshing];
});
});
}
显然,这也会涉及retrieveData
的一些变化,但希望这是自我解释的。如果没有,请使用该代码更新您的问题,我们可以提出进一步的建议。但我们真的不应该去那里,因为我怀疑你了解那里需要发生的变化。
您还可能需要解决其他更微妙的问题,例如考虑您是否真的想要使用并发的全局队列(例如,如果您在之前的刷新过程中点击刷新,那么你真的吗?希望与您的服务器同时进行两次查询...因为您将更新发送回主队列,您不会崩溃,但效率低下,您无法保证他们将完成的订单等等。您可能还想使用NSOperationQueue
来编写代码以允许取消先前的请求等。
但所有这一切都有点复杂,并且是你的主要问题,即崩溃的次要问题。重构retrieveData
代码以确保您不会触及citiesArray
,如上所述,应该解决这个问题。