【问题标题】:Swift 2.1 do-try-catch not catching errorSwift 2.1 do-try-catch 未捕获错误
【发布时间】:2016-05-21 18:11:48
【问题描述】:

这是我的 Swift 2.1 代码 sn-p。正在发生的错误会显示在错误出现点的 cmets 中。

调试面板中出现错误,应用程序崩溃。应用从不打印 catch 中的行,也不会像预期的那样优雅地返回。

let audioFileURL = receivedAudio.filePathURL

guard let audioFile = try? AVAudioFile(forReading: audioFileURL) else {
    print("file setup failed")
    return
}

let audioFileFrameCount = AVAudioFrameCount(audioFile.length)

audioFileBuffer = AVAudioPCMBuffer(PCMFormat: audioFile.fileFormat, frameCapacity: audioFileFrameCount)

do {
    // ERROR: AVAudioFile.mm:263: -[AVAudioFile readIntoBuffer:frameCount:error:]: error -50
    // Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -50'
    // -50 = Core Audio: bad param
    try audioFile.readIntoBuffer(audioFileBuffer)
}
catch {
    print("unable to load sound file into buffer")
    return
}

从我所看到的一切来看,我的 do/try/catch 格式应该是正确的。

audioFile.readIntoBuffer 返回void 并具有关键字throws

然而,catch 永远不会被执行。

我错过了什么?

更新:From Apple's documentation on AVAudioFile

为:

func readIntoBuffer(_ buffer: AVAudioPCMBuffer) throws

讨论中:

在 SWIFT 中处理错误:

在 Swift 中,此 API 作为初始化程序导入,并使用 throws 关键字进行标记,以指示在失败的情况下它会抛出错误。

您在 try 表达式中调用此方法并处理 do 语句的 catch 子句中的任何错误,如 Swift 编程语言 (Swift 2.1) 中的错误处理和将 Swift 与 Cocoa 和 Objective-C 一起使用中的错误处理中所述(斯威夫特 2.1)。

来自The Swift Programming Language (Swift 2.1): Error Handline

注意

Swift 中的错误处理类似于其他语言中的异常处理,使用 try、catch 和 throw 关键字。与许多语言(包括 Objective-C)中的异常处理不同,Swift 中的错误处理不涉及展开调用堆栈,这是一个计算成本很高的过程。因此,throw 语句的性能特征与 return 语句的性能特征相当。

最后,来自同一个文档:

使用 Do-Catch 处理错误

您使用 do-catch 语句通过运行代码块来处理错误。如果 do 子句中的代码抛出错误,则将其与 catch 子句进行匹配,以确定其中哪一个可以处理错误。

我不必编写和抛出我自己的错误/异常来捕获它们。我应该也能捕捉到 Swift 的异常。

【问题讨论】:

  • catch 只会捕获明确抛出的错误。它不会捕获异常。您在这里似乎遇到的是 AVAudioFile SDK 中发生的异常,而不是 Swift 错误,因此没有被捕获。
  • 我添加了一个更新,其中包括可互换使用术语 errorsexceptions 的 Apple 文档:Error handling in Swift 类似于其他语言中的 exception 处理,使用 try、catch 和 throw 关键字。 它应该适用于两者!
  • 在 Swift 的上下文中,“错误”是指一个函数抛出的错误,不管是不是你的,仅此而已。 永远不会捕获 Swift 中的异常。例如,它与 Java 完全不同。我理解您的观点,即“它应该适用于两者”,但事实并非如此。如果需要,您可以使用关键字“catch”将其视为语义情况,因为它与其他语言的关键字相同,但行为却截然不同。它类似,但不是。 :)
  • 鉴于编程指南中的措辞,您可以理解我的困惑,@Eric D.。我会进一步研究。
  • @Johannes:我没有找到原因。该错误意味着“错误的参数”,但可能是由甚至与该代码行无关的其他事情引起的。相反,我使用了一种不同的技术来处理音频。该项目采用 Swift 2.1,位于 GitHub,如果您想看看。

标签: ios swift2 try-catch


【解决方案1】:

do - catch 组合很好。这个问题只是一个无法捕获的问题 - 因此永远不会出现在 catch 块中。

如果问题是可捕获的(通过 Swift 的 throws 功能定义和处理),catch 块将被执行。


一些语义:关于术语 errorexception 之间的区别存在长期争论。

一些开发人员认为这两个术语是不同的。在这种情况下,术语 error 表示设计为要处理的问题。斯威夫特的throws 行动适合这里。在这种情况下,do - catch 组合将允许发现问题。

异常,对于这些开发人员来说,代表无法捕捉和处理的意外问题,通常是致命问题。 (一般情况下,就算能抓到,也拿不动。)

其他人认为这两个术语是等效的且可以互换的,无论是否可以发现相关问题。 (Apple 的文档似乎遵循了这一理念。)

(已更新以关注答案而不是语义。)

【讨论】:

    【解决方案2】:

    catch 只会捕获明确抛出的错误。它永远不会捕获异常。

    您在这里似乎遇到的是 AVAudioFile SDK 中发生的异常,而不是 Swift 错误,因此没有被捕获:

    错误:AVAudioFile.mm:263:-[AVAudioFile readIntoBuffer:frameCount:error:]:错误-50
    由于未捕获的异常“com.apple.coreaudio.avfaudio”而终止应用程序,原因:“错误 -50”
    -50 = 核心音频:参数错误

    在 Swift 的上下文中,“错误”是指由函数抛出的错误,仅此而已。功能是否属于你并不重要。

    Swift 中的异常永远不会被捕获。例如,它与 Java 完全不同。在 Swift 中,error != exception 是两个非常不同的东西。

    我理解您的观点,即“两者都应该适用”,但事实并非如此。如果需要,您可以将其视为使用关键字“catch”的语义情况,因为它与其他语言的关键字相同,但行为却截然不同;很像,但又不一样。

    至于您对 AVAudioFile 的异常,我没有解决方案 - 也许这是此 SDK 中的错误?或者它还没有正确绑定到 Swift 和投掷系统。在这种情况下,如果没有其他人有解决方案,请不要犹豫,将错误报告给 Apple。

    【讨论】:

    • 1.同样,Apple 的文档可以互换使用这些术语。无论如何,这里的概念是正确的(直到我发布了自己的答案,我才看到这个答案)。 2.“雷达”不是官方的错误报告网站,Apple 也不阅读它。如果他们愿意,可以由单个开发人员将问题添加到“雷达”。我通过 Apple 自己的错误报告网站报告错误,该网站可供会员中心的付费开发人员使用。
    【解决方案3】:

    看这个例子

    struct E: ErrorType{}
    
    func foo(i: Int) throws {
        if i == 0 {
            throw E()
        }
        print(10 / (i - 1))
    }
    
    do {
        //try foo(1) // if you uncomment this line, the execution 
        // will crash, even though the function is declared 
        // as throwing and you use proper calling style (do / try / catch pattern)
        try foo(0)
    } catch {
        print("error: ", error) // error: E()
    }
    

    【讨论】:

    • throws 处理不限于您自己的自定义函数。正如我在更新中提到的,Swift 的 AVAudioFile 文档特别指出 您在 try 表达式中调用此方法并处理 do 语句的 catch 子句中的任何错误 ... - 和 init(forReading fileURL: NSURL) 抛出
    • @leanne 我没这么说!似乎,在 Swift 2.1 API 到 AVFoundation 框架中存在一个错误(一些可能的错误没有被抛出,这就是为什么你的代码会因异常而崩溃)。我注意到在你的回答下方,但有人删除了我的笔记......在我的笔记中,我向你的问题的投票者询问了他的动机,因为你的方法对我来说似乎没问题。
    • @leanne 顺便说一句,问题在于 func readIntoBuffer(_ buffer: AVAudioPCMBuffer) throws ,而不是 init(forReading fileURL: NSURL) throws 。您的 audioFileBuffer 是如何声明的(从您的 sn-p 中不清楚)?
    • 谢谢,@user3441734。我希望你能支持我的问题,因为你认为这很好。此外,我已更正了函数名称 - 适用于该函数的文档是相同的。我将在一个新问题中发布 sn-p 的缓冲区部分,询问为什么会出现问题。此外,消失的笔记也很奇怪。我认为只有发表评论的人或版主才能删除 cmets。很高兴您在这里澄清。
    猜你喜欢
    • 2014-03-04
    • 2015-08-23
    • 1970-01-01
    • 2022-12-21
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    相关资源
    最近更新 更多