如何记录在Xcode中显示为运行时问题的警告?

时间:2017-09-22 20:12:16

标签: ios xcode ios11 xcode9

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

enter image description here

enter image description here

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

7 个答案:

答案 0 :(得分:1)

是的!如果您执行清洁剂捕获的操作,您将会看到这些内容,例如在启用了Thread Sanitizer的后台线程中执行某些UI操作。在视图调试器中具有模糊布局和暂停也是实现此目的的一种方法。无论哪种方式,看到苹果公司的图书馆出现这种情况都不是一件好事......

答案 1 :(得分:1)

  

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

答案 2 :(得分:1)

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

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

如果您不是这样做的话,在 XCode 9 中有一个名为主线程检查器的功能。

有关详细信息,请访问以下网址:https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

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

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

答案 3 :(得分:1)

XCode 8.3 及更早版本中,您可以将set breakpoint用于任何UIKit类的方法,如下面的setNeedsDisplay()

在objective-c steipete类中还有一个库,其中使用了#import <objc/runtime.h>

enter image description here

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

答案 4 :(得分:1)

嗯,这是一个hack,远非理想之举,但可以有效地获取运行时警告,而不会出现断言或致命错误等游戏结束行为:

auth.createUserWithEmailAndPassword(email, password)
                        .addOnCompleteListener(CurrentActivity.this, new OnCompleteListener<AuthResult>() {
                            @Override
                            public void onComplete(@NonNull Task<AuthResult> task) {
                                Toast.makeText(SignupActivity.this, "createUserWithEmail:onComplete:" + task.isSuccessful(), Toast.LENGTH_SHORT).show();
                                // If sign in fails, display a message to the user. If sign in succeeds
                                // the auth state listener will be notified and logic to handle the
                                // signed in user can be handled in the listener.
                                if (!task.isSuccessful()) {
                                    Toast.makeText(SignupActivity.this, "Authentication failed." + task.getException(),
                                            Toast.LENGTH_SHORT).show();
                                } else {
                                    //Do something here
                                    startActivity(new Intent(CurrentActivity.this, RedirectActivity.class));
                                    finish();
                                }
                            }
                        });

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

用法和结果与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 } } assertionFailure非常相似:

fatalError

在控制台中显示消息:

runtimeWarning("Hi, I'm purple")

还有这个,所以您不会错过它:

Runtime issue

答案 5 :(得分:0)

  

here
  一旦您通过App Store或作为Ad Hoc或Enterprise版本部署了应用程序,您就无法将Xcode的调试器附加到其中。要调试问题,您需要分析设备的崩溃日志和控制台输出。

     

Apple Watch崩溃日志将在配对设备上提供,也可以使用下述方法获取。

     

有关编写丰富的 NSLog 语句的详细信息,请参阅Improved logging in Objective-C

将示例代码粘贴到项目中:

NSMutableArray *someObject = [NSMutableArray array];
NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);
[someObject addObject:@"foo"];
NSLog(@"%s:%d someObject=%@", __func__, __LINE__, someObject);

答案 6 :(得分:0)

对于任何好奇的人来说,只是想添加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)
    }
}
相关问题