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

时间:2022-03-14 07:41:05

I would really like to use a more simple classic try catch block in my Swift code but I can't find anything that does it.

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

I just need:

我只需要:

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

Here's my dilema, when the TableView is reloaded with new data, some information is still siting in RAM which calls didEndDisplayingCell on a tableView with a freshly empty datasource to crash.

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

So I frequently thrown the exception Index out of range

所以我经常抛出异常索引超出范围

I've tried this:

我试过这个:

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...")
    }
}

I've also tried this:

我也试过这个:

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

This is a very low priority block of code, and I have wasted a lot of time with trial and error figuring out which error handler built into swift works for what seems to be extremely unique situations when I have tons of scenarios just like this one where the code can crash and it will not have any effect on the user experience.

这是一个非常低优先级的代码块,我浪费了大量的时间进行试验和错误,弄清楚swift中构建的哪个错误处理程序适用于看起来非常独特的情况,当我有大量的场景就像这样的情况代码可能崩溃,它不会对用户体验产生任何影响。

In short, I don't need anything fancy but Swift seems to have extremely specific error handlers that differ based on whether I'm getting a value from a functions return value or getting a value from an array's index which may not exist.

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

Is there a simple try catch on Swift like every other popular programming language?

像其他流行的编程语言一样,是否有一个简单的尝试捕获Swift?

4 个解决方案

#1


26  

As suggested in comments and other answers it is better to avoid this kind of situations. However, in some cases you might want to check if an item exists in an array and if it does safely return it. For this you can use the below Array extension for safely returning an array item.

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

Swift 3

斯威夫特3

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

Swift 2

斯威夫特2

extension Array {
    subscript (safe index: Int) -> Element? {
        return indices ~= index ? self[index] : nil
    }
}
  • This way you'll never hit Index out of range
  • 通过这种方式,您永远不会将Index超出范围
  • You'll have to check if the item is nil
  • 你必须检查项目是否为零

refer this question for more

请参考这个问题


Trying the Swift3 code in a Playground in Xcode 8.3.2 still leads to a "crash" when I do let ar = [1,3,4], then let v = ar[5]. Why? – Thomas Tempelmann May 17 at 17:40

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

You have to use our customized subscript so instead of let v = ar[5], it wll be let v = ar[safe: 5].

你必须使用我们的自定义下标,而不是让v = ar [5],它将被赋予v = ar [safe:5]。

Default getting value from array.

默认从数组中获取值。

let boo = foo[index]

Add use the customized subscript.

添加使用自定义下标。

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
}

#2


23  

Swift's Error Handling (do/try/catch) is not the solution to runtime exceptions like "index out of range".

Swift的错误处理(do / try / catch)不是像“索引超出范围”这样的运行时异常的解决方案。

A runtime exception (you might also see these called trap, fatal error, assertion failure, etc.) is a sign of programmer error. Except in -Ounchecked builds, Swift usually guarantees that these will crash your program, rather than continuing to execute in a bad/undefined state. These sorts of crashes can arise from force-unwrapping with !, implicit unwrapping, misuse of unowned references, integer operations/conversions which overflow, fatalError()s and precondition()s and assert()s, etc. (And, unfortunately, Objective-C exceptions.)

运行时异常(您可能还会看到这些称为陷阱,致命错误,断言失败等)是程序员错误的标志。除了-Ounchecked构建之外,Swift通常会保证它们会使程序崩溃,而不是继续以错误/未定义的状态执行。这些类型的崩溃可能来自强制解包!,隐式解包,滥用无主引用,整数操作/转换溢出,fatalError()和precondition()s和assert()等等。(不幸的是, Objective-C例外。)

The solution is to simply avoid these situations. In your case, check the bounds of the array:

解决方案是简单地避免这些情况。在您的情况下,检查数组的边界:

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

(Or, as rmaddy says in comments — investigate why this problem is occurring! It really shouldn't happen at all.)

(或者,正如rmaddy在评论中所说 - 调查为什么会出现这个问题!它根本不应该发生。)

#3


1  

You can try a different approach to this. Will surely work!

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

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

#4


0  

Swift 4:

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

Usage:

用法:

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

or

要么

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

#1


26  

As suggested in comments and other answers it is better to avoid this kind of situations. However, in some cases you might want to check if an item exists in an array and if it does safely return it. For this you can use the below Array extension for safely returning an array item.

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

Swift 3

斯威夫特3

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

Swift 2

斯威夫特2

extension Array {
    subscript (safe index: Int) -> Element? {
        return indices ~= index ? self[index] : nil
    }
}
  • This way you'll never hit Index out of range
  • 通过这种方式,您永远不会将Index超出范围
  • You'll have to check if the item is nil
  • 你必须检查项目是否为零

refer this question for more

请参考这个问题


Trying the Swift3 code in a Playground in Xcode 8.3.2 still leads to a "crash" when I do let ar = [1,3,4], then let v = ar[5]. Why? – Thomas Tempelmann May 17 at 17:40

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

You have to use our customized subscript so instead of let v = ar[5], it wll be let v = ar[safe: 5].

你必须使用我们的自定义下标,而不是让v = ar [5],它将被赋予v = ar [safe:5]。

Default getting value from array.

默认从数组中获取值。

let boo = foo[index]

Add use the customized subscript.

添加使用自定义下标。

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
}

#2


23  

Swift's Error Handling (do/try/catch) is not the solution to runtime exceptions like "index out of range".

Swift的错误处理(do / try / catch)不是像“索引超出范围”这样的运行时异常的解决方案。

A runtime exception (you might also see these called trap, fatal error, assertion failure, etc.) is a sign of programmer error. Except in -Ounchecked builds, Swift usually guarantees that these will crash your program, rather than continuing to execute in a bad/undefined state. These sorts of crashes can arise from force-unwrapping with !, implicit unwrapping, misuse of unowned references, integer operations/conversions which overflow, fatalError()s and precondition()s and assert()s, etc. (And, unfortunately, Objective-C exceptions.)

运行时异常(您可能还会看到这些称为陷阱,致命错误,断言失败等)是程序员错误的标志。除了-Ounchecked构建之外,Swift通常会保证它们会使程序崩溃,而不是继续以错误/未定义的状态执行。这些类型的崩溃可能来自强制解包!,隐式解包,滥用无主引用,整数操作/转换溢出,fatalError()和precondition()s和assert()等等。(不幸的是, Objective-C例外。)

The solution is to simply avoid these situations. In your case, check the bounds of the array:

解决方案是简单地避免这些情况。在您的情况下,检查数组的边界:

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

(Or, as rmaddy says in comments — investigate why this problem is occurring! It really shouldn't happen at all.)

(或者,正如rmaddy在评论中所说 - 调查为什么会出现这个问题!它根本不应该发生。)

#3


1  

You can try a different approach to this. Will surely work!

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

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

#4


0  

Swift 4:

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

Usage:

用法:

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

or

要么

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