Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Do I Recover a Stack Trace in Swift?

Tags:

swift

How do I recover the stack trace in Swift, so that I can find out which method was the last one called before a crash?

What I want to replicate in Swift is this method in C#:

public static Assembly GetComponentInInvocationDegree(int invocationDegree)
    {
        if (invocationDegree < 0) throw new ArgumentOutOfRangeException("Cannot set out of range value: invocation degree must be greater than or equal to zero");

        var stackInvocacion = new StackTrace().GetFrames();
        if (invocationDegree > 0)
        {
            int invokingAssemblyIndex = 0;
            string currentDegreeComponentName;
            try
            {
                for (int currentDegree = 0; currentDegree < invocationDegree; currentDegree++)
                {
                    currentDegreeComponentName = stackInvocacion[invokingAssemblyIndex].GetMethod().ReflectedType.Assembly.GetName().Name;
                    while (stackInvocacion[invokingAssemblyIndex].GetMethod().ReflectedType.Assembly.GetName().Name == currentDegreeComponentName) invokingAssemblyIndex++;                        
                }
            }
            catch (Exception ex) { throw new InvalidOperationException(string.Format("Cannot get component in invocation degree: invocation degree {0} does not exist", invocationDegree), ex); }

            return stackInvocacion[invokingAssemblyIndex].GetMethod().ReflectedType.Assembly;
        }

        return stackInvocacion[0].GetMethod().ReflectedType.Assembly;
    }
like image 518
Holtrod Avatar asked Jul 13 '15 22:07

Holtrod


2 Answers

In many cases, you could use a try/catch mechanism.

do {
    try ... // risky business goes here
} catch let error as NSError {
    print("Error: \(error.domain)")
    println(NSThread.callStackSymbols())
}     

Swift errors have no such thing as stack-trace yet (if will ever), and even Xcode can show stack-trace only if the error is un-handled by our code (and gets caught by Xcode directly instead).

Alternativly, your custom Error's constructor can store the stack-trace for later use, but in most cases errors are not custom, where you can't alter error's constructor (like errors of 3rd-party library).

Exception breakpoint

If you just want to debug, without need to upload stack-trace to server, then Xcode's "Exception breakpoint" feature can help, like:

  • First place a normal-breakpoint near the failing logic.

  • Wait until Xcode pauses App on that line, enable Xcode's feature:

  • Finally, resume App, and wait untill exception is thrown.

Images are old, nowadays you see "Swift error breakpoint" or something like that as well (beside "Add Exception Breakpoint" option).

like image 75
SwiftArchitect Avatar answered Nov 18 '22 16:11

SwiftArchitect


In swift 3 and above, you can do it like this:

do {
    //....
}
catch {
    print("error occurred")
    print(Thread.callStackSymbols)
}
like image 2
david euler Avatar answered Nov 18 '22 15:11

david euler