【问题标题】:Is there a way to catch or handle EXC_BAD_ACCESS?有没有办法捕捉或处理 EXC_BAD_ACCESS?
【发布时间】:2013-04-18 14:19:16
【问题描述】:

据我了解,EXC_BAD_ACCESS 发生在您尝试访问坏内存时(如果我错了,请随时纠正我)?

有没有办法像在try-catch 中那样在Java 中捕获它以防止应用程序完全失败?

【问题讨论】:

    标签: iphone ios objective-c exc-bad-access


    【解决方案1】:

    如果你想用闭包捕获或处理崩溃,你可以使用https://github.com/dhatbj/SignalRecovery

    C 代码 func 宏在 swift 中不可用,不能直接调用函数(signal_try、signal_catch、signal_end) 这是一个如何将闭包作为函数参数传递的示例。

    首先我们需要将完成块传递给 C 代码并返回信号错误。

    将此代码添加到 signal_recovery.h:

    const char* signalTry(void (*block)(void));
    

    将此代码添加到 signal_recovery.c:

    const char* signalTry(void (*block)(void)) {
        
        const char* signalName = "";
        
        signal_try(label0) {
            block();
        }
        signal_catch(label0) {
            signalName = signal_name(signal_info()->si_signo);
        }
        signal_end(label0)
        
        return signalName;
    }
    

    在 swift 代码中,您需要调用 C 函数 signalTry 并将闭包作为参数传递给它:

    import // C files   
    
    class ExceptionsHandler {    
        
            private static var isReady = false
            
            init() {
                if !Self.isReady {
                    Self.isReady = true
                    signal_catch_init()
                }
            }
            
            private func cFunction(_ block: @escaping @convention(block) () -> Void) -> (@convention(c) () -> Void) {
                return unsafeBitCast(imp_implementationWithBlock(block), to: (@convention(c) () -> Void).self)
            }
            
            func execute(_ block: @escaping () -> Void) throws {
               
                let cBlock: @convention(c) () -> Void = cFunction {
                    block()
                }
        
                let error = signalTry(cBlock)
        
                if let error = error, !String(cString: UnsafePointer<CChar>(error)).isEmpty {
                    print("Catched signal \(String(cString: UnsafePointer<CChar>(error)))")
                    throw \\ error or exception
                }
            }
        }
    

    当闭包 block() 中发生错误 EXC_BAD_ACCESS 时,此 C 函数将跳过它,您将捕获它而不会崩溃。

    像这样:

    try self.exceptionsHandler.execute {
                let a = 3
                let b = 0
                let c = a / b
    
                // or
                let testArray: [Int] = []
                let number = testArray[100]
            }
    

    【讨论】:

      【解决方案2】:

      新的 C 库SignalRecovery 可以使程序能够从操作系统异常中恢复,例如EXC_BAD_ACCESS。 可以在IOS/MacOS/Linux中使用。

      示例代码:

      signal_try(label) {
          // Add your code need try.
          int* ptr = NULL;
          *ptr = 0;
      }
      signal_catch(label) {
          // Add your code to process exceptions, or do nothing.
          siginfo_t* info = signal_info();
      }
      signal_end(label)
      // Continue run
      

      【讨论】:

      • 你能帮我多做一点吗?我应该如何将这个库集成到我的 XCode 项目中以及如何使用它。在这里获取 EXC_BAD_ACCESS: func addAck(_ ack: Int, callback: @escaping AckCallback) { acks.insert(SocketAck(ack: ack, callback: callback)) // 在这一行 }
      【解决方案3】:

      可以使用 try catch,但您首先需要知道导致问题的原因。您可以为当前构建启用 NSZombie 以捕获错误并消除需要。编辑当前方案,启用 NSZombie。

      • 更新 * Swift2+ 现在具有出色的错误处理能力,绝对值得一试。 Swift Error Handling

      【讨论】:

      • 这不能回答问题,应该是评论。
      【解决方案4】:

      有时可以使用信号处理程序在main 中捕获它。但是,除了记录一些东西之外,它不允许您做太多事情。

      【讨论】:

        【解决方案5】:

        不; EXC_BAD_ACCESS 表示事情已经严重脱轨。您的程序正在尝试访问无效的内存地址。 IE。内存已损坏且无法恢复。

        这可能是内存管理问题。如果您可以重现该问题,请打开 NSZombies 并查看会发生什么。或者在这里发布回溯。

        请注意,try-catch 样式的异常在 iOS/Cocoa 中也是不可恢复的。异常不能用于可恢复的错误处理。这就是 NSError 的用途。

        【讨论】:

        • 关于“try-catch 样式的异常在 iOS 中是不可恢复的”——这对我来说似乎不太正确。 某些异常不能被@try / @catch捕获,但其他的可以;我认为后者是“可恢复的”,就像任何其他具有异常捕获机制的现代语言一样。
        • @ToolmakerSteve 根据定义,iOS 中的异常不被视为可恢复的。这就是 NSError 远的地方。其他现代语言所做的完全无关紧要。您可以选择不这样做,但这样做与记录的、推荐的模式背道而驰,因此您将追逐奇怪的行为和/或崩溃错误。
        • 谢谢。 iOS实际上做什么会“将异常视为不可恢复”。您能否指出一个文档或其他讨论使用异常如何导致“追逐奇怪行为或崩溃错误”的文档或其他线程。 【已有跨平台代码;想要对重组这一切的原因做出更明确的陈述,而不仅仅是“Apple 说要,每个人都说“哦,最好不要使用例外。”]
        • @ToolmakerSteve 当抛出一个通过系统框架中的任何帧的异常时,行为是未定义的。它可能会泄漏、可能无法清理和/或可能导致其他未定义的行为。见developer.apple.com/library/content/documentation/Cocoa/…见页面顶部的重要块。
        • 谢谢。事实上,我已经阅读了该警告,但我没有找到任何 Apple 文档或第三方线程说明 为什么在什么情况下 存在问题。您证实了我的怀疑:问题是对系统的任何调用都没有定义如果异常试图解除调用时会发生什么。在我看来,应用程序的唯一限制是任何回调必须最迟在回调的根方法中捕获异常。否则,我看不出堆栈展开中将如何涉及任何系统框架。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-05-21
        • 1970-01-01
        • 1970-01-01
        • 2012-04-07
        • 2022-07-26
        • 2020-03-27
        • 2011-02-09
        相关资源
        最近更新 更多