【问题标题】:How to log a warning that shows up as a runtime issue in Xcode?如何记录在 Xcode 中显示为运行时问题的警告?
【发布时间】:2018-03-04 11:53:23
【问题描述】:

Xcode 8 或 9 开始显示运行时问题。您会在窗口顶部看到一个紫色图标,并在问题导航器中看到一个列表,旁边是编译警告和错误等构建时问题。

我看到的运行时问题是由系统库造成的。有没有办法让我自己的应用程序代码生成这些?

【问题讨论】:

  • 我认为你目前还不能......
  • 不可能精确地得到你想要的,但如果你详细说明你想要实现的目标或你想要解决的问题,我们可能会提供一个替代解决方案。

标签: ios xcode ios11 xcode9


【解决方案1】:

只是想为任何好奇的人添加一个runtimeWarning 方法的 Swift 实现:

func runtimeWarning(_ message: String) {
    // Load the dynamic library.
    guard let handle = dlopen(nil, RTLD_NOW) else {
        fatalError("Couldn't find dynamic library for runtime warning.")
    }

    // Get the "__main_thread_checker_on_report" symbol from the handle.
    guard let sym = dlsym(handle, "__main_thread_checker_on_report") else {
        fatalError("Couldn't find function for runtime warning reporting.")
    }

    // Cast the symbol to a callable Swift function type.
    typealias ReporterFunction = @convention(c) (UnsafePointer<Int8>) -> Void
    let reporter = unsafeBitCast(sym, to: ReporterFunction.self)

    // Convert the message to a pointer
    message.withCString { messagePointer in
        // Call the reporter with the acquired messagePointer
        reporter(messagePointer)
    }
}

【讨论】:

    【解决方案2】:

    嗯,这是一个 hack,远非理想,但对于获取运行时警告很有用,而不会出现断言或致命错误等游戏结束行为:

    func runtimeWarning(_ message: String, file: String = #file, line: Int = #line) {
        #if DEBUG
        DispatchQueue.global(qos: .userInteractive).async {
            // If you got here, please check console for more info
            _ = UIApplication.shared.windows
            print("Runtime warning: \(message): file \(file.fileName), line \(line)")
        }
        #endif
    }
    
    fileprivate extension String {
        var fileName: String { URL(fileURLWithPath: self).lastPathComponent }
    }
    

    不幸的是,这会导致从主线程检查器向控制台打印相当大的内容,也没有显示在正确的行上,但至少您在控制台中拥有所需的所有信息(包括您应该检查的代码行)。

    用法和结果与assertionFailurefatalError非常相似:

    runtimeWarning("Hi, I'm purple")
    

    在控制台中显示消息:

    Runtime warning: Hi, I'm purple: file MyFile.swift, line 10

    还有这个,所以你不会错过的:

    【讨论】:

    • 别等了,这真是个肮脏的……把戏,哈哈,我明白你在那里做了什么,基石就是访问UIApplication.shared.windows,呜呜……
    【解决方案3】:

    是的!如果您执行 sanitizer 捕获的操作,例如在启用了 Thread Sanitizer 的后台线程中执行某些 UI 操作,您将看到这些。在视图调试器中使用不明确的布局和暂停也是实现此目的的一种方法。无论哪种方式,在 Apple 的库中看到这种情况都不是一件好事……

    更新:我研究了这些警告是如何发生的,LLDB 本质上是在一组魔术函数上设置断点(__asan::AsanDie()__tsan_on_report__ubsan_on_report__main_thread_checker_on_report)在问题发生时调用的消毒剂动态库内部。如果您定义自己版本的这些函数并调用它们,您将收到警告。首先,在项目的某处创建符号:

    void __main_thread_checker_on_report(char *message) {
    }
    

    然后您可以随意触发它,只需将此代码放在应用程序中的任何位置(您可能希望将其隐藏在宏后面):

    ((void (*)(char *))dlsym(dlopen(NULL, RTLD_LAZY), "__main_thread_checker_on_report")))("This will show up as a warning")
    

    不用说,如果您选择使用它,它几乎肯定不会与实际的消毒剂配合得很好。您可能应该根据您是否使用消毒剂有条件地编译上述内容。

    【讨论】:

    • 我认为,问题的关键在于能够随意“手动”生成自定义运行时问题。
    • 你可以随意创建这些吗?是的,如果你做了上面列出的任何事情。你能把它作为一种日志记录或调试工具吗?不,不是。这不是它应该用于的。
    • 嗯,在我看来,它实际上应该用于:) 不是用于一般日志记录,而是用于快速解决突出的运行时问题,能够查看其他元数据并跳转快速找到导致它的代码位置。这将是非常棒的。并且基于对这个问题的兴趣,看起来很多人都同意。但是,是的,很可能这是不可能的。如果有人出现并告诉我们确实如此,那就太酷了。
    • 嗯,你总是可以用assertionFailure 或类似的方法杀死你的程序以获得类似的效果,但它有停止你的程序的副作用。我知道你想要的东西是多么有用,所以我建议向 Apple 提交一个错误,看看他们是否会向用户公开。
    • @FreeNickname 经过进一步检查,如果您跳过一些障碍,您的问题的答案实际上是“是”。查看我的更新。
    【解决方案4】:

    XCode 8.3 及更早版本中,您可以在 UIKit 类的任何方法中使用设置断点,如下所示 setNeedsDisplay()

    objective-c steipete 类中还有一个库,其中使用了#import &lt;objc/runtime.h&gt;

    但在 Xcode 9 中,库 Xcode.app/Contenets/Developer/usr/lib/libMainThreadChecker.dylib 是可用的,它可以处理运行时可能在主线程外执行的任何相关问题。

    【讨论】:

      【解决方案5】:

      这取决于你是否在其他主线程上执行任何与 UI 相关的工作,因此系统将为你生成,否则你无法手动生成它。

      所有 UI 操作都应在主线程中完成。

      如果您不这样做,在 XCode 9 中具有称为 主线程检查器 的功能。

      欲了解更多信息,您可以访问以下网址:https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

      它主要用于检查是否有任何UIKit 相关的东西在主线程上发生?,如果没有这样做,它将在运行时产生问题。因此,将您的代码包装在 Main Thread 块中,如下所示,以避免出现故障和运行时警告。

      您可以启用-禁用使用此步骤编辑方案...->(选择您的方案)->诊断->禁用“主线程检查器”

      【讨论】:

        【解决方案6】:

        CocoaLumberjack 框架可用于捕获运行时控制台日志以及应用程序的后台唤醒日志。

        https://github.com/CocoaLumberjack/CocoaLumberjack

        https://github.com/phonegap/phonegap-plugin-push/issues/1988

        通过这种方式,您可以在 App Container 中维护的文件中捕获 Xcode9 中显示的紫色警告,如下所示:-

        ================================================ ===================

        主线程检查器:在后台线程上调用的 UI API:-[UIApplication registerUserNotificationSettings:] PID:2897,TID:1262426,线程名称:(无),队列名称:com.apple.root.default-qos,QoS:21

        【讨论】:

          猜你喜欢
          • 2012-10-28
          • 2012-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多