我如何在Swift中捕捉“索引超出范围”?

我真的想在我的Swift代码中使用更简单的经典try catch块,但是我找不到任何可以做到的事情。

我只需要:

try { // some code that causes a crash. } catch { // okay well that crashed, so lets ignore this block and move on. } 

这里是我的困境,当TableView重新加载新数据时,一些信息仍然在RAM中,在一个tableView上调用了didEndDisplayingCell ,一个新的空数据源崩溃。

所以我经常抛出exceptionIndex out of range

我试过这个:

 func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { do { let imageMessageBody = msgSections[indexPath.section].msg[indexPath.row] as? ImageMessageBody let cell = tableView.dequeueReusableCellWithIdentifier("ImageUploadCell", forIndexPath: indexPath) as! ImageCell cell.willEndDisplayingCell() } catch { print("Swift try catch is confusing...") } } 

我也试过这个:

 func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { print(indexPath.section) print(indexPath.row) if msgSections.count != 0 { if let msg = msgSections[indexPath.section].msg[indexPath.row] as? ImageMessageBody { let cell = tableView.dequeueReusableCellWithIdentifier("ImageUploadCell", forIndexPath: indexPath) as! ImageCell cell.willEndDisplayingCell() } } } 

这是一个非常低优先级的代码块,我浪费了大量的时间,试着找出哪些error handling程序内置到swift中,当我拥有像这样的场景的情况下,似乎是非常独特的情况代码可能会崩溃,并且不会对用户体验产生任何影响。

总之,我不需要什么奇特的东西,但Swift似乎有非常具体的error handling程序,根据我是从函数返回值获取值还是从数组的索引中获取值可能不存在不同。

是否有像所有其他stream行的编程语言一样简单的Swift尝试?

Swift的error handling ( do / try / catch不是像“索引超出范围”的运行时exception的解决scheme。

运行时exception(您也可能会看到这些称为陷阱致命错误断言失败等)是程序员错误的标志。 除非-Ounchecked构build,Swift通常保证这些将会崩溃你的程序,而不是继续执行一个坏/未定义的状态。 这些崩溃可能会从强制解包出来! ,隐式解包,滥用unowned引用,溢出的整数运算/转换, fatalError() s和precondition() s和assert()等等(不幸的是,Objective-Cexception)。

解决办法是简单地避免这些情况 。 你的情况,检查数组的边界:

 if indexPath.section < msgSections.count && indexPath.row < msgSections[indexPath.section].msg.count { let msg = msgSections[indexPath.section].msg[indexPath.row] // ... } 

(或者,正如rmaddy在评论中所说 – 调查为什么会发生这个问题!这真的不应该发生。)

正如评论和其他答案中所build议的,最好避免这种情况。 但是,在某些情况下,您可能需要检查数组中是否存在项目,以及是否安全地返回它。 为此,您可以使用下面的Array扩展来安全地返回数组项。

Swift 3

 extension Collection where Indices.Iterator.Element == Index { subscript (safe index: Index) -> Generator.Element? { return indices.contains(index) ? self[index] : nil } } 

Swift 2

 extension Array { subscript (safe index: Int) -> Element? { return indices ~= index ? self[index] : nil } } 
  • 这样你永远不会打 Index out of range
  • 你将不得不检查项目是否nil

参考这个问题更多


当我让ar = [1,3,4],然后让v = ar [5]时,在Xcode 8.3.2的Playground中尝试Swift3代码仍然会导致“崩溃”。 为什么? – 托马斯·坦珀尔曼5月17日17:40

你必须使用我们自定义的下标,而不是let v = ar[5] ,它let v = ar[safe: 5]

默认从数组中获取值。

 let boo = foo[index] 

添加使用自定义的下标。

 let boo = fee[safe: index] // And we can warp the result using guard to keep the code going without throwing the exception. guard let boo = foo[safe: index] else { return } 

你可以尝试一个不同的方法。 肯定会工作!

 if msgSections != nil { for msg in msgSections[indexPath.section] { if msgSections[indexPath.section].index(of: msg) == indexPath.row { (Code) } }