TabBarController:Going Tab-To-Tab - 致命错误:数组索引超出范围
Posted
技术标签:
【中文标题】TabBarController:Going Tab-To-Tab - 致命错误:数组索引超出范围【英文标题】:TabBarController: Going Tab-To-Tab - fatal error: Array index out of range 【发布时间】:2015-09-09 15:47:33 【问题描述】:我有一个带有两个选项卡的 TabBarController(一个 TableViewController,一个 CollectionViewController)。当我从一个选项卡切换到另一个选项卡时,我的应用程序有时会崩溃。它总是在 UITableViewController 选项卡上崩溃,这是一个简单的 Feed。显示以下断点和信息:
0x498e44 <+68>: bl 0x4efb9c ; function signature specialization <Arg[0] = Exploded, Arg[1] = Exploded> of Swift.(_fatalErrorMessage (Swift.StaticString, Swift.StaticString, Swift.StaticString, Swift.UInt) -> ()).(closure #2)
-> 0x498e48 <+72>: trap // **This is the breakpoint
在 FeedView 中,我有以下内容,并在第 3 行找到了另一个断点:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as! FeedViewCell
let currentItem = feedItems[indexPath.row] // **Other error breakpoint occurs here
let date = currentItem.createdAt
let formatter = NSDateFormatter()
formatter.dateFormat = "hh:mm"
let dateString = formatter.stringFromDate(date!)
cell.userName?.text = currentItem.userName
cell.itemName?.text = currentItem.itemName
cell.timeStamp?.text = dateString
// MARK: Setup image for cell
cell.itemImage?.image = UIImage(named: "1.png")
let image = currentItem.imageFile
image.getDataInBackgroundWithBlock (imageData: NSData?, error: NSError?) -> Void in
if !(error != nil)
cell.itemImage?.image = UIImage(data: imageData!)
cell.imageView?.contentMode = .ScaleAspectFit
cell.imageView?.clipsToBounds = true
return cell
func getAndShowFeedItems() // I call this in ViewWillAppear
feedItems.removeAll(keepCapacity: false)
let getFeedItems = FeedItem.query()
getFeedItems!.orderByDescending("createdAt")
getFeedItems!.findObjectsInBackgroundWithBlock (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil
for object in objects!
self.feedItems.append(object as! FeedItem)
if self.feedItems.count == 35
break
else if error!.code == PFErrorCode.ErrorConnectionFailed.rawValue
self.showNetworkAlert()
print("there's a networking problem")
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
self.resetUserDefaults()
self.scrollToFirstRow()
注意:我使用 Parse.com 作为我的图像存储,venueImage
是一个 PFImage,它不允许我像 UIImage
那样打开图像。
【问题讨论】:
【参考方案1】:您在 getAndShowFeedItems 方法中有错误。服务器请求可能需要更多时间。您正在清理您的阵列,但不要重新加载表格视图。如果在获取项目之前滚动表视图,则会发生崩溃。您需要为此更改代码:
func getAndShowFeedItems() // I call this in ViewWillAppear
feedItems.removeAll(keepCapacity: false)
self.tableView.reloadData() // Need reload tableview when change it content
let getFeedItems = FeedItem.query()
getFeedItems!.orderByDescending("createdAt")
getFeedItems!.findObjectsInBackgroundWithBlock (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil
for object in objects!
self.feedItems.append(object as! FeedItem)
if self.feedItems.count == 35
break
else if error!.code == PFErrorCode.ErrorConnectionFailed.rawValue
self.showNetworkAlert()
print("there's a networking problem")
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
self.resetUserDefaults()
self.scrollToFirstRow()
您在 cellForRowAtIndexPath 部分也有错误。滚动时可以设置错误的图像。因为表格视图会重复使用不可见的单元格。因此,当您完成下载图像数据单元格时,可能包含错误的 indexPath。你可以像这样修改你的代码。
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCellWithIdentifier("feedCell", forIndexPath: indexPath) as! FeedViewCell
let currentItem = feedItems[indexPath.row] // **Other error breakpoint occurs here
let date = currentItem.createdAt
let formatter = NSDateFormatter()
formatter.dateFormat = "hh:mm"
let dateString = formatter.stringFromDate(date!)
cell.userName?.text = currentItem.userName
cell.itemName?.text = currentItem.itemName
cell.timeStamp?.text = dateString
// MARK: Setup image for cell
if let image = UIImage(data: currentItem.imageData)
cell.itemImage?.image = image
cell.imageView?.contentMode = .ScaleAspectFit
cell.imageView?.clipsToBounds = true
else
cell.itemImage?.image = UIImage(named: "1.png")
let image = currentItem.imageFile
image.getDataInBackgroundWithBlock (imageData: NSData?, error: NSError?) -> Void in
if !(error != nil)
currentItem.imageData = imageData!
let index = feedItems.indexOfObject(currentItem)
if index != NSNotFound
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .None)
return cell
代码可能包含一些我不编译它的不准确之处。您还需要在类 currentItem 变量中添加新属性。
【讨论】:
这有效 - 感谢您的解决方案!加载时间增加了一点,但这比崩溃要好。 :) 您可以在加载前显示上一个项目。你需要在块中移动feedItems.removeAll(keepCapacity: false)
。【参考方案2】:
这里有一个基本的设计错误。您正在尝试获取单元格的数据并使用该块进行设置。但是单元格对象会被重用,一旦表格视图离开屏幕,所有单元格都可能与表格解除关联。您需要做的是获取数据,填充您的模型(即数组或字典),然后向主线程发布一个需要刷新某行的块。如果显示该行,您可以从 tableview 中获取它(通过可见单元格数组)。如果它没有显示,什么也不做,当你被要求输入单元格时,你将拥有数据来填充它。
我在我的应用程序中所做的是使用一个单独的方法来获取单元格、其索引并更新单元格内容。当我被要求提供一个新单元时,我分配一个,然后调用此方法。当我收到某种内部通知表明可见单元格信息可能已更改时,我会调用相同的方法(重点是您将编写单元格内容的代码放在一个地方,而不是两个地方)。
编辑:再次,您的问题在这里:
(imageData: NSData?, error: NSError?) -> Void in
if !(error != nil)
cell.itemImage?.image = UIImage(data: imageData!)
cell.imageView?.contentMode = .ScaleAspectFit
cell.imageView?.clipsToBounds = true
您正在保存对“单元格”的引用,该引用将来对于您要保存在其中的信息无效,并且单元格本身可能已被释放。
当数据从后台进来时,向主线程发布一个块并将其保存在数组或字典中。然后,相同的方法可以更新所有可见单元格。您不需要 NSNotification 来执行此操作 - 在主线程上发布一个块就可以了。
【讨论】:
很好的答案,但您不再需要为您的表格分配单元格。如果没有可用的单元格,dequeueReusableCellWithIdentifier:
现在会分配适当类型的新单元格。
@Caleb 不想学究气——我在 iPad 上回答这个问题,而不是在 Mac 上,所有 api 都摆在我面前。你引用的这个方法返回一个单元格——这就是我所说的“分配”。核心答案是 - 不要认为您可以在将来的某个时候访问数据的温和持有者(“单元格”)。它是显示数据的临时占位符。
我指出的原因是,在较旧的 ios 版本(iOS 6 之前)中,您必须检查 dequeueReusableCellWithIdentifier:
的结果,如果为零,您必须自己使用 @ 分配一个新单元格987654324@ 和init
。所以,就像我说的,很好的答案——我只是认为,如果读者碰巧在看一个较旧的例子,其中一个部分可能会引起一些混乱。
谢谢@DavidH - 这就是我从您的回复中收集到的信息,如果我理解正确,请告诉我。您建议我不要在cellForRow
.. 中设置我的单元格,而是将其写入一个单独的方法中。当需要一个新的单元格时(在这种情况下您指的是cellForRow..
吗?),您运行deqeueReusable
... 然后调用单元格方法?另外,对于可见单元格更改的内部通知,您是否建议我使用NSNotification
?以上是关于TabBarController:Going Tab-To-Tab - 致命错误:数组索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章
错误形式(在 com.going.books.MainActivity.onCreate(MainActivity.java:19))
php Event Tickets Plus:禁止与会者修改其与会者信息,他们的RSVP“Going / Not Going”状态和/或他们的“Do”的能力