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

问题描述 投票:0回答:6

我真的很想在我的 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
来崩溃。

所以我经常抛出异常

Index 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()
        }
    }
}

这是一个非常低优先级的代码块,当我有大量像这样的场景时,我浪费了大量的时间来反复试验,找出 swift 中内置的哪个错误处理程序适用于似乎非常独特的情况代码可能会崩溃,但不会对用户体验产生任何影响。

简而言之,我不需要任何花哨的东西,但 Swift 似乎有非常具体的错误处理程序,这些处理程序根据我是从函数返回值获取值还是从可能不存在的数组索引获取值而有所不同。

Swift 上有像其他流行编程语言一样简单的 try catch 吗?

ios swift uitableview
6个回答
75
投票

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

斯威夫特5

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

斯威夫特4

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

斯威夫特3

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

斯威夫特2

extension Array {
    subscript (safe index: Int) -> Element? {
        return indices ~= index ? self[index] : nil
    }
}
  • 这样你就永远不会打到
    Index out of range
  • 您必须检查该商品是否
    nil

参考这个问题了解更多


在 Xcode 8.3.2 的 Playground 中尝试 Swift3 代码仍然会导致 当我先让 ar = [1,3,4],然后让 v = ar[5] 时,会发生“崩溃”。为什么? ——托马斯 坦佩尔曼 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
}

34
投票

Swift 的错误处理

do
/
try
/
catch
不是解决运行时异常(如“索引超出范围”)。

运行时异常(您可能还会看到这些称为 trapfatal errorassertion failure 等)是程序员错误的标志。除了在

-Ounchecked
构建中,Swift 通常保证这些会导致你的程序崩溃,而不是继续在错误/未定义的状态下执行。此类崩溃可能是由于使用 ! 强制展开、隐式展开、误用
unowned
引用、溢出的整数运算/转换、
fatalError()
precondition()
assert()
等引起的。(不幸的是,Objective-C 也有例外。)

解决方案就是简单地

避免这些情况

。在您的情况下,检查数组的边界: if indexPath.section < msgSections.count && indexPath.row < msgSections[indexPath.section].msg.count { let msg = msgSections[indexPath.section].msg[indexPath.row] // ... }

(或者,正如 rmaddy 在评论中所说 - 调查
为什么

这个问题发生!它真的根本不应该发生。)


31
投票

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

用法

var index :Int = 6 // or whatever number you need if let _ = myArray[exist: index] { // do stuff }

var index :Int = 6 // or whatever number you need guard let _ = myArray[exist: index] else { return }



2
投票

这个

Swift 5中的答案变成: extension Collection where Indices.Iterator.Element == Index { subscript (safe index: Index) -> Iterator.Element? { return indices.contains(index) ? self[index] : nil } }

另外,从 
Swift 4

开始,可以在关联类型上使用子句,它可以变成: extension Collection { subscript (safe index: Index) -> Element? { return indices.contains(index) ? self[index] : nil } }



2
投票

guard array.indices.contains(index) else { return }



1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.