Using the Debugger

When an application is launched from Xcode, the debugger is attached to that application. The debugger monitors the current state of the application, like what method it is currently executing and the values of the variables that are accessible from that method. Using the debugger can help you understand what an application is actually doing, which, in turn, helps you find and fix bugs.

One way to use the debugger is to set a breakpoint. Setting a breakpoint on a line of code pauses the execution of the application at that line (before it executes). This is useful when your application is not doing what you expected and you need to look at what is really happening.

In WhereamiAppDelegate.m, find the first line of code in application:​didFinishLaunchingWithOptions: where you instantiate the CLLocationManager. Set a breakpoint by clicking the gutter (the lightly shaded bar on the left side of the editor area) next to that line of code. The blue indicator shows you where the application will break the next time you run it (Figure 4.6).

Figure 4.6  A breakpoint

A breakpoint

Build and run the application. The application will start and then stop before the first line of application:​didFinishLaunchingWithOptions: is executed. Notice the green indicator that appears on the same line as the breakpoint. This indicator shows you the current point of execution.

Now our application is temporarily frozen in time, and we can examine it more closely. In the navigator area, click the A breakpoint icon to open the debug navigator. This navigator shows a stack trace of where the breakpoint stopped execution. The slider at the bottom of the debug navigator expands and collapses the stack. Drag it to the right to see all of the methods in the stack trace. (Figure 4.7).

Figure 4.7  The debug navigator

The debug navigator

The method where the break occurred is at the top of the stack trace. It was called by the method just below it, which was called by the method just below it, and so on. This chain of method calls continues all the way back to main. Notice that the two methods that you implemented are in black text and the methods Apple implemented are in gray.

Select the method at the top of the stack. This will display the implementation of application:​didFinishLaunchingWithOptions: in the editor area. Below the editor area, check out the variables view to the left of the console. This area shows the variables available within the scope of this method along with their current values (Figure 4.8).

Figure 4.8  Debug area with Variables View

Debug area with Variables View

(If you don’t see the variables view, find the Debug area with Variables View control above the console. Click the center button to see both the console and the variables view.)

In the variables view, a variable that is a pointer to an object shows the object’s address in memory. (There are some exceptions, like NSString, where the actual string is shown instead.) A variable that is a primitive, like int, shows its actual value.

Now click the disclosure button next to self. The first item under self is its superclass. In the context of this method, self is a pointer to the instance of WhereamiAppDelegate, so its superclass is NSObject. Clicking the disclosure button next to NSObject shows what self inherits from its superclass.

After the superclass, you can check out the object’s instance variables, which for WhereamiAppDelegate, is just locationManager. The breakpoint is set to the line that creates the instance of CLLocationManager and assigns it to locationManager. That line of code has yet to be executed, so locationManager is still set to nil (0x0).

In addition to giving you a snapshot of the application at a given point, the debugger also allows you to step through your code line by line and watch the behavior of your application as each line executes. The buttons that control the execution are on the debugger bar. This bar sits between the editor area and the debug area (Figure 4.9).

Click the button to step over a line. This will execute just the current line of code, which instantiates the CLLocationManager. Notice that the green execution indicator moves to the next line. Even more interesting, the variables view shows that the value of locationManager has changed to a valid address in memory – this object is now alive and well.

Figure 4.9  Debugger bar

Debugger bar

At this point, you could continue stepping through the code to see what happens. Or you could click the button to continue executing your code normally. Or you could step into a method. Stepping into a method takes you to the method that is called by the line of code that currently has the green execution indicator. Once you’re in the method, you have the chance to step through its code in the same way.

Let’s add a method that we can step into and out of. Declare the following method in WhereamiAppDelegate.h.

#​i​m​p​o​r​t​ ​<​U​I​K​i​t​/​U​I​K​i​t​.​h​>​
#​i​m​p​o​r​t​ ​<​C​o​r​e​L​o​c​a​t​i​o​n​/​C​o​r​e​L​o​c​a​t​i​o​n​.​h​>​

@​i​n​t​e​r​f​a​c​e​ ​W​h​e​r​e​a​m​i​A​p​p​D​e​l​e​g​a​t​e​ ​:​ ​N​S​O​b​j​e​c​t​
 ​ ​ ​ ​<​U​I​A​p​p​l​i​c​a​t​i​o​n​D​e​l​e​g​a​t​e​,​ ​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​D​e​l​e​g​a​t​e​>​
{​
 ​ ​ ​ ​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​*​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​;​
}​
@​p​r​o​p​e​r​t​y​ ​(​n​o​n​a​t​o​m​i​c​,​ ​r​e​t​a​i​n​)​ ​I​B​O​u​t​l​e​t​ ​U​I​W​i​n​d​o​w​ ​*​w​i​n​d​o​w​;​

-​ ​(​v​o​i​d​)​d​o​S​o​m​e​t​h​i​n​g​W​e​i​r​d​;​

@​e​n​d​

In WhereamiAppDelegate.m, implement this method to log some stuff to the console.

-​ ​(​v​o​i​d​)​d​o​S​o​m​e​t​h​i​n​g​W​e​i​r​d​
{​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​L​i​n​e​ ​1​"​)​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​L​i​n​e​ ​2​"​)​;​
 ​ ​ ​ ​N​S​L​o​g​(​@​"​L​i​n​e​ ​3​"​)​;​
}​

Next in WhereamiAppDelegate.m, send this message to the instance of WhereamiAppDelegate in application:​didFinishLaunchingWithOptions:.

-​ ​(​B​O​O​L​)​a​p​p​l​i​c​a​t​i​o​n​:​(​U​I​A​p​p​l​i​c​a​t​i​o​n​ ​*​)​a​p​p​l​i​c​a​t​i​o​n​
 ​ ​ ​ ​d​i​d​F​i​n​i​s​h​L​a​u​n​c​h​i​n​g​W​i​t​h​O​p​t​i​o​n​s​:​(​N​S​D​i​c​t​i​o​n​a​r​y​ ​*​)​l​a​u​n​c​h​O​p​t​i​o​n​s​
{​
 ​ ​ ​ ​/​/​ ​C​r​e​a​t​e​ ​l​o​c​a​t​i​o​n​ ​m​a​n​a​g​e​r​ ​o​b​j​e​c​t​ ​-​
 ​ ​ ​ ​/​/​ ​i​t​ ​w​i​l​l​ ​s​e​n​d​ ​i​t​s​ ​m​e​s​s​a​g​e​s​ ​t​o​ ​o​u​r​ ​W​h​e​r​e​a​m​i​A​p​p​D​e​l​e​g​a​t​e​
 ​ ​ ​ ​l​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​=​ ​[​[​C​L​L​o​c​a​t​i​o​n​M​a​n​a​g​e​r​ ​a​l​l​o​c​]​ ​i​n​i​t​]​;​

 ​ ​ ​ ​[​s​e​l​f​ ​d​o​S​o​m​e​t​h​i​n​g​W​e​i​r​d​]​;​

Finally, drag your breakpoint to this newly-implemented line. Build and run the application.

When the execution halts, click the button to step into this method. The execution indicator will jump inside the doSomethingWeird method to the first line of its implementation. Now click the button to step over a line. The line of code that logs Line 1 will execute, and you will see its text in the console.

The execution indicator is now at the statement that logs Line 2. If you’ve decided that you’ve seen enough of this fascinating method, you can click the button to step out of it. Notice that the rest of the log statements appear in the console, and the execution indicator is now back in application:​didFinishLaunchingWithOptions: – right after the call to doSomethingWeird. This behavior is important to understand: when you step out of a method, you don’t cancel its execution; the method will finish normally and return to the code that called it.

To remove the breakpoint, simply drag it off the gutter. Or click the Debugger bar icon in the navigator selector to reveal the breakpoint navigator and see all the breakpoints in your project. From there, you can select a breakpoint and delete it.

Sometimes, a new developer will set a breakpoint and forget about it. Then, when the application is run, execution stops, and it looks like the application has crashed. If you can’t make out why an application of yours has crashed, make sure you aren’t stopped on a forgotten breakpoint.

While you can set breakpoints to break on a particular line, the debugger will break on any line that causes your application to crash or that causes an exception to be thrown. Let’s introduce an exception to see this happen. In WhereamiAppDelegate.m, delete the entire implementation of doSomethingWeird (not just the code inside the method’s brackets, but the method signature, too). Leave the line in application:​didFinishLaunchingWithOptions: that sends the doSomethingWeird message and leave the declaration in the header file.

Now WhereamiAppDelegate no longer implements this method, and when it sends this message to self, an exception will be thrown. Build and run the application.

Immediately after launch, the application will blow up. The debugger will show you where (look for the green execution indicator), and the console will show you why. Notice that the stack trace is a bit longer this time, and the method that caused the exception is not at the top of the stack trace. This will sometimes be the case: your code supplies bad data (like an unrecognized selector) to a method, and then somewhere within that method’s implementation, the application crashes. To find the source of the error, look for your methods in the stack trace. The culprit may not be at the top, but it will certainly be one of yours.

Also notice that the compiler warned you that the method definition was not found for doSomethingWeird. This means you declared a method in the header file but did not implement it. Remove the declaration of doSomethingWeird from WhereamiAppDelegate.h and build again. This time, you will see a different warning at the point where doSomethingWeird is sent to self. Now the compiler is telling you that this method doesn’t exist at all.

Remove the line of code that sends doSomethingWeird to self. Your application should run correctly again. Build and run to make sure before heading to the next chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.83.151