如何从崩溃日志中找到正在发生的确切异常或根本原因 ios
How to find the exact exception that's being occured or the root cause from the crash logs ios
我创建了一个手表应用程序,它对我来说运行良好,而其他人则指出发生了崩溃。因此,由于我无法重新创建,所以我从 xcode 中找到了该版本的崩溃日志,崩溃日志如下所示,
Incident Identifier: AE2591FC-4E97-4EE4-8E9A-3CA6480A2EDF
Hardware Model: Watch5,9
Process: watch Extension [276]
Path: /private/var/containers/Bundle/Application/E2F3129B-4EF2-4C80-A0D4-82D246A39F32/watch.app/PlugIns/watch Extension.appex/watch Extension
Identifier: //app id
Version: 7 (4.1.0)
AppVariant: 1:Watch5,9:7
Beta: YES
Code Type: ARM (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: // [378]
Date/Time: 2021-11-04 16:38:59.1335 +0530
Launch Time: 2021-11-04 16:31:54.0000 +0530
OS Version: Watch OS 7.3.3 (18S830)
Release Type: User
Baseband Version: n/a
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000022ce5c88
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [276]
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libswiftCore.dylib 0x22ce5c88 _assertionFailure(_:_:file:line:flags:) + 356 (AssertCommon.swift:132)
1 libswiftCore.dylib 0x22d3d12c swift_unexpectedError + 300 (ErrorType.swift:188)
2 watch Extension 0x04488074 closure #1 in OtpView.fetchProfile() + 1232 (OtpView.swift:203)
3 watch Extension 0x0443c47c specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 1120 (Inteceptor.swift:0)
4 watch Extension 0x0443dc80 partial apply for specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 72 (<compiler-generated>:0)
5 watch Extension 0x04438a38 thunk for @escaping @callee_guaranteed () -> () + 20 (<compiler-generated>:0)
6 libdispatch.dylib 0x2a5901bc _dispatch_client_callout + 16 (object.m:559)
7 libdispatch.dylib 0x2a593344 _dispatch_continuation_pop + 492 (inline_internal.h:2548)
8 libdispatch.dylib 0x2a5a3eb0 _dispatch_source_invoke + 1272 (source.c:570)
9 libdispatch.dylib 0x2a59ce58 _dispatch_main_queue_callback_4CF + 556 (inline_internal.h:2589)
10 CoreFoundation 0x20110eec __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 (CFRunLoop.c:1790)
11 CoreFoundation 0x2010b428 __CFRunLoopRun + 2452 (CFRunLoop.c:3118)
12 CoreFoundation 0x2010a574 CFRunLoopRunSpecific + 572 (CFRunLoop.c:3242)
13 GraphicsServices 0x348904c0 GSEventRunModal + 160 (GSEvent.c:2259)
14 UIKitCore 0x24f95adc -[UIApplication _run] + 1104 (UIApplication.m:3253)
15 UIKitCore 0x24f9afdc UIApplicationMain + 140 (UIApplication.m:4707)
16 WatchKit 0x2703dc30 WKApplicationExtensionMain + 312 (main.m:131)
17 SwiftUI 0x28a3b628 runApp<A>(_:) + 196 (WatchKitRenderer.swift:34)
18 SwiftUI 0x28957d6c static App.main() + 80 (App.swift:113)
19 watch Extension 0x044288c8 $main + 24 (<compiler-generated>:10)
20 watch Extension 0x044288c8 main + 36 (Observables.swift:0)
21 WatchKit 0x26f6694c WKExtensionMain + 608 (main.m:102)
22 libdyld.dylib 0x3591191c start + 4
...
enter image description here
我不确定错误发生在哪里以及为什么会发生。谁能指导我解决这个问题?
我的 swift 相关问题的代码如下所示,
/*
* © Copyrights
* All Rights Reserved.
*
*
*
*
*
*
*
*
*/
import SwiftUI
struct OtpView: View {
private let placeholder: String = "Enter the 6 digit OTP here"
@State private var input:String = "Enter the 6 digit OTP here";
@State private var navigateToNext: Bool = false;
@State private var isVisible: Bool = false;
@State private var alertMessage: String = "";
@State private var isFetching: Bool = false;
init(){
input=self.placeholder;
}
var body: some View {
// NavigationView{
ZStack{
AlertView(isVisible: $isVisible,
message: self.alertMessage,
onHide: {
if self.isVisible {
self.isVisible.toggle();
}
})
if self.isFetching {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
GeometryReader{
geometry in
let width = geometry.size.width;
let height = geometry.size.height;
VStack(alignment:.leading){
Text(input)
.font(.system(size:14.0,design: .rounded))
.multilineTextAlignment(.trailing)
.frame(width:width)
.lineLimit(1)
NavigationLink(destination:HomeView(),
isActive: $navigateToNext){
}
.frame(width:0,height:0)
HStack(){
Spacer()
GradientButton(buttonTitle: "NEXT"){
self.validateOtp()
}
Spacer()
}
.frame(width: width)
.padding([.bottom,.top], 5.0)
Divider()
Spacer()
VStack(){
ForEach(buttonList, id: \.self){
row in
HStack(){
ForEach(row, id:\.self){
button in
Button(action: {
if self.input == self.placeholder {
if button != "del"{
input = button;
}
}else{
if button != "del" {
input.count != 6 ?
input += button : nil
}else{
if input.count == 1 {
input = self.placeholder
}else{
input = String(input.dropLast())
}
}
}
}){
if button != "del" {
Text(button)
.font(.system(size:14.0,design: .rounded))
.frame(minWidth:(width/4), idealWidth: (width/4), maxWidth:(width/4),
maxHeight:.infinity)
} else {
Image("Delete")
.resizable()
.frame(width:18, height:16)
.padding()
}
}
.frame(minWidth:(width/4), idealWidth: (width/4), maxWidth:width/3-10,
minHeight:height/6,
idealHeight: height/6,
maxHeight: height/6)
.cornerRadius(50.0)
.buttonStyle(PlainButtonStyle())
if button != "3" && button != "6" && button != "9" && button != "del" {
Spacer()
}
}
}
}
}
}
}
.blur(radius: isVisible || self.isFetching ? 3.0 : 0)
.disabled(isVisible)
}
// }
.navigationBarBackButtonHidden(false)
.navigationTitle("OTP")
.onDisappear(perform: {
print("GOINF FROM OTP")
})
}
func validateOtp(){
if input != self.placeholder && input.count == 6 && isStringContainsOnlyNumbers(string:input){
self.isFetching.toggle();
let requestHeader = getRequestHeader(action:”NO_ACTION”);
guard let id = requestHeader[“id”] else {
return;
}
let request = [
“Validate”:[
“name”:GlobalData.name,
"deviceId":"N/A",
"detail”: [
"action”:”NO_ACTION”,
"otp":self.input
],
],
"requestHeader": requestHeader
] as [String : Any]
useInteceptor(urlString: ncellUrls[“URL1”] ?? "",method: "POST", requestBody: request){ data, error, displayCode in
self.isFetching.toggle();
if let data = data {
let validateOtpResponse = try! JSONDecoder().decode(ValidateOtpResponse.self, from: data);
if let userAuth = validateOtpResponse.validateOTPResponse {
self.isFetching.toggle();
self.fetchProfile();
// self.navigateToNext.toggle();
}
} else {
self.alertMessage = getErrorMessage(code: displayCode)
self.isVisible.toggle();
}
}
}else{
self.alertMessage = "Please enter a valid Otp to proceed."
self.isVisible.toggle();
}
}
func fetchProfile(){
let request = [
“getProfile”:[
“name”:GlobalData.name,
“Id”: "1",
],
"requestHeader": getRequestHeader(action:”ACTION1”)
]
useInteceptor(urlString: ncellUrls[“URL2”] ?? "",method: "POST", requestBody: request){ data, error, displayCode in
self.isFetching.toggle();
if let data = data {
let profile = try! JSONDecoder().decode(ProfileResponse.self, from: data);
if let ratePlanDetails = profile.response?.detail {
self.navigateToNext.toggle();
}
} else {
self.alertMessage = getErrorMessage(code: displayCode)
self.isVisible.toggle();
}
}
}
}
struct OtpView_Previews: PreviewProvider {
static var previews: some View {
OtpView()
}
}
无关,但在Swift中,行尾不需要;
。
让我们阅读崩溃日志:
2 watch Extension 0x04488074 closure #1 in OtpView.fetchProfile() + 1232 (OtpView.swift:203)
3 watch Extension 0x0443c47c specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 1120 (Inteceptor.swift:0)
4 watch Extension 0x0443dc80 partial apply for specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 72 (<compiler-generated>:0)
这是有趣的部分(顶部有方法名称的部分),您从底部开始阅读它们。
因此在 Interceptor.swift
中,方法 useInteceptor(urlString:method:requestBody:completionHandler:)
在某个时候被调用。
在这一个中,有一个 closure
(或多个),但至少在第一个 (closure #1
) 中,即 completionHandler
,你调用 [=19= OptView.swift
文件中 OptView
class 的 ]。
在那里,在第 203 行,这是导致崩溃的行。
我们来分析一下罪魁祸首:
let profile = try! JSONDecoder().decode(ProfileResponse.self, from: data)
这里,可能的崩溃是因为try!
。
为什么你使用 try!
而不是写 do
/try
/catch
?你知道你为什么在这里使用 force unwrap !
吗?什么意思?
这意味着如果抛出错误,只是让应用程序崩溃。
因此,如果发生崩溃,这是预期的行为,因为您明确写了“如果出现错误,请在此处崩溃”。
那么,现在,为什么 decode(_:from:)
会崩溃?
我不知道 ProfileResponse
是什么,但该方法可能会引发错误,因为您没有指定 JSON 中的值可以是 nul,JSON 中的值可以省略,因为接收到的JSON还有一个问题,或者JSON无效。
或者,因为您的 API 给出了错误的值。有时 API 遇到错误时,他们会回复:{"error": "some reason why it failed"}
。这是一个有效的 JSON,但我认为 ProfileResponse
不会像那样。
现在,为什么它会给出错误的响应,这取决于您的 Web API,检查文档,检查 API 开发人员以获得可能的响应:您是否使用了错误的参数,您是否属于这种情况?由后端处理?
所以当你用 try!
写那一行时,你决定告诉:“不要担心响应,如果有响应,我确信它可以被解码进入一个 ProfileResponse
对象。相信我,我知道我在做什么,我保证它永远有效,如果不是这样,就崩溃,那会证明我错了,但请放心,我我对自己有把握”。是的,这意味着 try!
.
不想死机就不要用!
,写个属性do
/try
/catch
。
do {
let profile = try JSONDecoder().decode(ProfileResponse.self, from: data)
if let ratePlanDetails = profile.response?.detail {
self.navigateToNext.toggle()
}
} catch {
print("Oops, there was an error while decoding ProfileResponse: \(error)")
print("And the API response was: \(String(data: data, encoding: .utf8) ?? "unknown data")")
}
现在,至于为什么你有一个无效的响应,这取决于你的调试:尝试重现它,使用特定的参数、特定的案例等)。我们无法猜测出了什么问题,也无法猜测 API 返回的是什么。
一旦你知道你的 API 发回的真实响应是什么,并且不知道如何处理它,你可以在 SO 上提出一个新问题,我们可能会帮助你,但在这一点上,我们不能对您的问题做更多的事情。
我创建了一个手表应用程序,它对我来说运行良好,而其他人则指出发生了崩溃。因此,由于我无法重新创建,所以我从 xcode 中找到了该版本的崩溃日志,崩溃日志如下所示,
Incident Identifier: AE2591FC-4E97-4EE4-8E9A-3CA6480A2EDF
Hardware Model: Watch5,9
Process: watch Extension [276]
Path: /private/var/containers/Bundle/Application/E2F3129B-4EF2-4C80-A0D4-82D246A39F32/watch.app/PlugIns/watch Extension.appex/watch Extension
Identifier: //app id
Version: 7 (4.1.0)
AppVariant: 1:Watch5,9:7
Beta: YES
Code Type: ARM (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: // [378]
Date/Time: 2021-11-04 16:38:59.1335 +0530
Launch Time: 2021-11-04 16:31:54.0000 +0530
OS Version: Watch OS 7.3.3 (18S830)
Release Type: User
Baseband Version: n/a
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000022ce5c88
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [276]
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 libswiftCore.dylib 0x22ce5c88 _assertionFailure(_:_:file:line:flags:) + 356 (AssertCommon.swift:132)
1 libswiftCore.dylib 0x22d3d12c swift_unexpectedError + 300 (ErrorType.swift:188)
2 watch Extension 0x04488074 closure #1 in OtpView.fetchProfile() + 1232 (OtpView.swift:203)
3 watch Extension 0x0443c47c specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 1120 (Inteceptor.swift:0)
4 watch Extension 0x0443dc80 partial apply for specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 72 (<compiler-generated>:0)
5 watch Extension 0x04438a38 thunk for @escaping @callee_guaranteed () -> () + 20 (<compiler-generated>:0)
6 libdispatch.dylib 0x2a5901bc _dispatch_client_callout + 16 (object.m:559)
7 libdispatch.dylib 0x2a593344 _dispatch_continuation_pop + 492 (inline_internal.h:2548)
8 libdispatch.dylib 0x2a5a3eb0 _dispatch_source_invoke + 1272 (source.c:570)
9 libdispatch.dylib 0x2a59ce58 _dispatch_main_queue_callback_4CF + 556 (inline_internal.h:2589)
10 CoreFoundation 0x20110eec __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 (CFRunLoop.c:1790)
11 CoreFoundation 0x2010b428 __CFRunLoopRun + 2452 (CFRunLoop.c:3118)
12 CoreFoundation 0x2010a574 CFRunLoopRunSpecific + 572 (CFRunLoop.c:3242)
13 GraphicsServices 0x348904c0 GSEventRunModal + 160 (GSEvent.c:2259)
14 UIKitCore 0x24f95adc -[UIApplication _run] + 1104 (UIApplication.m:3253)
15 UIKitCore 0x24f9afdc UIApplicationMain + 140 (UIApplication.m:4707)
16 WatchKit 0x2703dc30 WKApplicationExtensionMain + 312 (main.m:131)
17 SwiftUI 0x28a3b628 runApp<A>(_:) + 196 (WatchKitRenderer.swift:34)
18 SwiftUI 0x28957d6c static App.main() + 80 (App.swift:113)
19 watch Extension 0x044288c8 $main + 24 (<compiler-generated>:10)
20 watch Extension 0x044288c8 main + 36 (Observables.swift:0)
21 WatchKit 0x26f6694c WKExtensionMain + 608 (main.m:102)
22 libdyld.dylib 0x3591191c start + 4
...
enter image description here
我不确定错误发生在哪里以及为什么会发生。谁能指导我解决这个问题?
我的 swift 相关问题的代码如下所示,
/*
* © Copyrights
* All Rights Reserved.
*
*
*
*
*
*
*
*
*/
import SwiftUI
struct OtpView: View {
private let placeholder: String = "Enter the 6 digit OTP here"
@State private var input:String = "Enter the 6 digit OTP here";
@State private var navigateToNext: Bool = false;
@State private var isVisible: Bool = false;
@State private var alertMessage: String = "";
@State private var isFetching: Bool = false;
init(){
input=self.placeholder;
}
var body: some View {
// NavigationView{
ZStack{
AlertView(isVisible: $isVisible,
message: self.alertMessage,
onHide: {
if self.isVisible {
self.isVisible.toggle();
}
})
if self.isFetching {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
GeometryReader{
geometry in
let width = geometry.size.width;
let height = geometry.size.height;
VStack(alignment:.leading){
Text(input)
.font(.system(size:14.0,design: .rounded))
.multilineTextAlignment(.trailing)
.frame(width:width)
.lineLimit(1)
NavigationLink(destination:HomeView(),
isActive: $navigateToNext){
}
.frame(width:0,height:0)
HStack(){
Spacer()
GradientButton(buttonTitle: "NEXT"){
self.validateOtp()
}
Spacer()
}
.frame(width: width)
.padding([.bottom,.top], 5.0)
Divider()
Spacer()
VStack(){
ForEach(buttonList, id: \.self){
row in
HStack(){
ForEach(row, id:\.self){
button in
Button(action: {
if self.input == self.placeholder {
if button != "del"{
input = button;
}
}else{
if button != "del" {
input.count != 6 ?
input += button : nil
}else{
if input.count == 1 {
input = self.placeholder
}else{
input = String(input.dropLast())
}
}
}
}){
if button != "del" {
Text(button)
.font(.system(size:14.0,design: .rounded))
.frame(minWidth:(width/4), idealWidth: (width/4), maxWidth:(width/4),
maxHeight:.infinity)
} else {
Image("Delete")
.resizable()
.frame(width:18, height:16)
.padding()
}
}
.frame(minWidth:(width/4), idealWidth: (width/4), maxWidth:width/3-10,
minHeight:height/6,
idealHeight: height/6,
maxHeight: height/6)
.cornerRadius(50.0)
.buttonStyle(PlainButtonStyle())
if button != "3" && button != "6" && button != "9" && button != "del" {
Spacer()
}
}
}
}
}
}
}
.blur(radius: isVisible || self.isFetching ? 3.0 : 0)
.disabled(isVisible)
}
// }
.navigationBarBackButtonHidden(false)
.navigationTitle("OTP")
.onDisappear(perform: {
print("GOINF FROM OTP")
})
}
func validateOtp(){
if input != self.placeholder && input.count == 6 && isStringContainsOnlyNumbers(string:input){
self.isFetching.toggle();
let requestHeader = getRequestHeader(action:”NO_ACTION”);
guard let id = requestHeader[“id”] else {
return;
}
let request = [
“Validate”:[
“name”:GlobalData.name,
"deviceId":"N/A",
"detail”: [
"action”:”NO_ACTION”,
"otp":self.input
],
],
"requestHeader": requestHeader
] as [String : Any]
useInteceptor(urlString: ncellUrls[“URL1”] ?? "",method: "POST", requestBody: request){ data, error, displayCode in
self.isFetching.toggle();
if let data = data {
let validateOtpResponse = try! JSONDecoder().decode(ValidateOtpResponse.self, from: data);
if let userAuth = validateOtpResponse.validateOTPResponse {
self.isFetching.toggle();
self.fetchProfile();
// self.navigateToNext.toggle();
}
} else {
self.alertMessage = getErrorMessage(code: displayCode)
self.isVisible.toggle();
}
}
}else{
self.alertMessage = "Please enter a valid Otp to proceed."
self.isVisible.toggle();
}
}
func fetchProfile(){
let request = [
“getProfile”:[
“name”:GlobalData.name,
“Id”: "1",
],
"requestHeader": getRequestHeader(action:”ACTION1”)
]
useInteceptor(urlString: ncellUrls[“URL2”] ?? "",method: "POST", requestBody: request){ data, error, displayCode in
self.isFetching.toggle();
if let data = data {
let profile = try! JSONDecoder().decode(ProfileResponse.self, from: data);
if let ratePlanDetails = profile.response?.detail {
self.navigateToNext.toggle();
}
} else {
self.alertMessage = getErrorMessage(code: displayCode)
self.isVisible.toggle();
}
}
}
}
struct OtpView_Previews: PreviewProvider {
static var previews: some View {
OtpView()
}
}
无关,但在Swift中,行尾不需要;
。
让我们阅读崩溃日志:
2 watch Extension 0x04488074 closure #1 in OtpView.fetchProfile() + 1232 (OtpView.swift:203)
3 watch Extension 0x0443c47c specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 1120 (Inteceptor.swift:0)
4 watch Extension 0x0443dc80 partial apply for specialized closure #1 in closure #1 in useInteceptor(urlString:method:requestBody:completionHandler:) + 72 (<compiler-generated>:0)
这是有趣的部分(顶部有方法名称的部分),您从底部开始阅读它们。
因此在 Interceptor.swift
中,方法 useInteceptor(urlString:method:requestBody:completionHandler:)
在某个时候被调用。
在这一个中,有一个 closure
(或多个),但至少在第一个 (closure #1
) 中,即 completionHandler
,你调用 [=19= OptView.swift
文件中 OptView
class 的 ]。
在那里,在第 203 行,这是导致崩溃的行。
我们来分析一下罪魁祸首:
let profile = try! JSONDecoder().decode(ProfileResponse.self, from: data)
这里,可能的崩溃是因为try!
。
为什么你使用 try!
而不是写 do
/try
/catch
?你知道你为什么在这里使用 force unwrap !
吗?什么意思?
这意味着如果抛出错误,只是让应用程序崩溃。
因此,如果发生崩溃,这是预期的行为,因为您明确写了“如果出现错误,请在此处崩溃”。
那么,现在,为什么 decode(_:from:)
会崩溃?
我不知道 ProfileResponse
是什么,但该方法可能会引发错误,因为您没有指定 JSON 中的值可以是 nul,JSON 中的值可以省略,因为接收到的JSON还有一个问题,或者JSON无效。
或者,因为您的 API 给出了错误的值。有时 API 遇到错误时,他们会回复:{"error": "some reason why it failed"}
。这是一个有效的 JSON,但我认为 ProfileResponse
不会像那样。
现在,为什么它会给出错误的响应,这取决于您的 Web API,检查文档,检查 API 开发人员以获得可能的响应:您是否使用了错误的参数,您是否属于这种情况?由后端处理?
所以当你用 try!
写那一行时,你决定告诉:“不要担心响应,如果有响应,我确信它可以被解码进入一个 ProfileResponse
对象。相信我,我知道我在做什么,我保证它永远有效,如果不是这样,就崩溃,那会证明我错了,但请放心,我我对自己有把握”。是的,这意味着 try!
.
不想死机就不要用!
,写个属性do
/try
/catch
。
do {
let profile = try JSONDecoder().decode(ProfileResponse.self, from: data)
if let ratePlanDetails = profile.response?.detail {
self.navigateToNext.toggle()
}
} catch {
print("Oops, there was an error while decoding ProfileResponse: \(error)")
print("And the API response was: \(String(data: data, encoding: .utf8) ?? "unknown data")")
}
现在,至于为什么你有一个无效的响应,这取决于你的调试:尝试重现它,使用特定的参数、特定的案例等)。我们无法猜测出了什么问题,也无法猜测 API 返回的是什么。 一旦你知道你的 API 发回的真实响应是什么,并且不知道如何处理它,你可以在 SO 上提出一个新问题,我们可能会帮助你,但在这一点上,我们不能对您的问题做更多的事情。