如何从崩溃日志中找到正在发生的确切异常或根本原因 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 上提出一个新问题,我们可能会帮助你,但在这一点上,我们不能对您的问题做更多的事情。