Xcode 8或9开始显示运行时问题。您会在窗口顶部看到一个紫色图标,并在Issue Navigator中看到一个列表,旁边是构建时间问题,如编译警告和错误。
我见过的运行时问题是由系统库创建的。有没有办法让我自己的应用程序代码生成这些?
答案 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>
。
但是在库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")
还有这个,所以您不会错过它:
答案 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)
}
}