© Radoslava Leseva Adams and Hristo Lesev 2016

Radoslava Leseva Adams and Hristo Lesev, Migrating to Swift from Flash and ActionScript, 10.1007/978-1-4842-1666-8_3

3. Introducing the Xcode Debugger

Radoslava Leseva Adams and Hristo Lesev2

(1)London, UK

(2)Kazanlak, Bulgaria

Having an integrated debugger is one of the best parts of using an integrated development environment (IDE). The easier and the more convenient a debugger is to use, the more regularly it will be put to work: without one you are shooting in the dark.

As you saw in the previous chapter, Xcode’s debugger automatically installs and runs apps for you on devices or in a simulator. Here you will familiarize yourself with the basic things the debugger can help you with: stepping through your code and inspecting values.

In this chapter you will do the following:

  • Extend the app you created in Chapter 2 and add Swift code to it.

  • Step through your code in the debugger.

  • Inspect variables and change their values at runtime.

  • Learn how to execute commands in Xcode’s console for simple diagnostics.

  • Have a peak at Xcode’s Memory view.

When you are done, you will have an idea of the debugging tools available to you in Xcode to help you stay in control of your code. In Chapter 8 , we will drill down into more advanced debugging topics.

Preparation: Write Code to Debug

In Chapter 2 we made a simple app that shows a date picker and a label. Let’s breathe some life into it by getting these user interface (UI) elements to do something interesting and make the label say what day of the week the date shown by the date picker is.

Starting Point: The HelloXcode App

If you followed the tutorial in Chapter 2 , you have an Xcode project, called HelloXcode, which builds an iOS app. Open it and in Project navigator find the ViewController.swift file. It contains the definition of a class called ViewController, which is responsible for the app’s main view and looks like Listing 3-1.

Listing 3-1. The ViewController Class with Outlets for a Label and a Date Picker
class ViewController: UIViewController {
    // Outlets for accessing the label and the date picker in Main.storyboard:
    @IBOutlet weak var dayOfTheWeek: UILabel!
    @IBOutlet weak var datePicker: UIDatePicker!


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view,
        // typically from a nib.
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

The two viewDidLoad and didReceiveMemoryWarning methods were put there by Xcode when it defined the ViewController class for us upon setting up the project. viewDidLoad is called when the view has been fully created and presented on the screen. didReceiveMemoryWarning will be executed in low-memory conditions, giving us a chance to release any unused memory.

In the course of Chapter 2 we added two UI controls to the main view’s storyboard: a date picker and a label. The IBOutlet members of the ViewController class give us access to these controls: dayOfTheWeek references the label and datePicker references the date picker. We had Xcode generate the IBOutlet definitions by dragging and dropping references from the storyboard into code.

Adding Action

The first piece of code we will add is an event handler, also known as action. It will be called when the date picker’s value changes. With Main.storyboard and ViewController.swift open in the Assistant editor side by side select and right-click the date picker on the storyboard. In the pop-up menu find the Value Changed event , then drag and drop the circle next to it into the ViewController class (Figure 3-1). This generates a method that will listen to and handle the Value Changed event for the date picker.

A371202_1_En_3_Fig1_HTML.jpg
Figure 3-1. Add a Value Changed event handler for the date picker

Name the event handler dateChanged and add the code in Listing 3-2 to it.

Listing 3-2. Implement the dateChanged Event Handler
@IBAction func dateChanged(sender: AnyObject) {
    updateDayOfWeek()
}

Updating the Label

At this point Xcode will complain that updateDayOfWeek is an “unresolved identifier.” This is because updateDayOfWeek is a method we haven’t implemented yet. Let us do that: add a new method to the ViewController class and have it update the label’s text (Listing 3-3).

Listing 3-3. Add a Method That Will Update the Label’s Text
func updateDayOfWeek() {
    // Change the label's text
    // to show what day of the week the date in the picker is:
    dayOfTheWeek.text = getDayOfWeek(date: datePicker.date)
}

It would be good if our label is synchronized with the date picker and shows the correct day of the week when the app first launches, so let us add a call to updateDayOfWeek to ViewController’s viewDidLoad method too (Listing 3-4).

Listing 3-4. Update the Label When the View Is First Loaded
override func viewDidLoad() {
    super.viewDidLoad()


    // Update the label when the view is first loaded:
    updateDayOfWeek()
}

Working Out the Day of the Week

getDayOfWeek(called in Listing 3-3) is another method that we need to implement: this is where we will work out the day of the week for the date shown by the picker. Listing 3-5 shows you the implementation of this method: it creates an instance of NSCalendar, which is part of the iOS SDK. The NSCalendar gives us access to the components (NSDateComponents) for a given date (NSDate) and these include the day of the week. Let us see how this works: implement the method as shown in Listing 3-5.

Listing 3-5. Work Out the Weekday from a Given Date
func getDayOfWeek(date date: NSDate) -> String {
    // The NSCalendar instance can give us access to the date components,
    // which have the weekday information:
    let gregorianCalendar =
        NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!


    // weekDay in an integer between 1 and 7:        
    let weekDay =
         gregorianCalendar.components
            ( NSCalendarUnit.Weekday, fromDate: date ).weekday


    // Now turn the integer into a day's name.
    // Keep in mind that the week in our chosen calendar starts on Sunday.
    switch weekDay {
        case 1: return "Sunday"
        case 2: return "Monday"
        case 3: return "Tuesday"
        case 4: return "Wednesday"
        case 5: return "Thursday"
        case 6: return "Friday"
        case 7: return "Saturday"


         // This will print out an error message in Xcode's console:
         default: print("weekDay must be between 1 and 7")
    }


    // We haven't been able to work out the weekday for some reason:
    return "Unknown"
}
Note

You may have noticed the additional date in getDayOfWeek(date date: NSDate) -> String. This is a parameter label. Labels help you document your code, especially at the point where you call a function that takes parameters. For example, getDayOfWeek would be called like this: getDayOfWeek(date: someDate). Here the label date serves as a reminder for what the parameter is intended to do. You can find out more about labeling parameters in Chapter 17.

Now, if you run the app in the simulator or on a device, you should be able to see the label get updated when you flick the date picker (Figure 3-2).

A371202_1_En_3_Fig2_HTML.jpg
Figure 3-2. The app now shows the day of week for the date in the picker

Getting Debug Information

Let us go over a few simple ways of getting inside information on what’s going on inside the app.

Using Print to Output to the Console

The simplest way to output runtime information in Xcode’s console is to call the print function.1 Activate the Standard editor (Figure 3-3); in Project navigator find the ViewController.swift file and open it. Locate and change the updateDayOfWeek function to print out what it’s doing (Listing 3-6).

A371202_1_En_3_Fig3_HTML.jpg
Figure 3-3. Using print to output to the console
Listing 3-6. Output Values to Xcode’s Console Using Print
func updateDayOfWeek() {
    // Change the label's text to show
    // what day of the week the date in the picker is:
    dayOfTheWeek.text = getDayOfWeek(date: datePicker.date)


    // Construct a string for the date in the date picker:
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .MediumStyle
    let dateString = dateFormatter.stringFromDate(datePicker.date)


    // Print out the date and what day of the week it is in Xcode's console:
    print("(dateString) is a (dayOfTheWeek.text!)")
}

The first three lines that we added to this function take the current date value from the date picker and run it through an instance of the NSDateFormatter class (part of the iOS SDK), so that we can get a nicely formatted string from it.

The last line is the interesting one: here we call the print function and ask it to output a string in Xcode’s console. This string is constructed from the value of the dateString variable and the label’s text. To insert a given value in a string literal, you wrap the value’s name in parentheses and prefix it with a backslash: (variableOrConstant); this goes inside the string literal quotes.

Run the app on your device or in a simulator to see the effect of printing into Xcode’s console. If the Debug area is not visible at the bottom of the screen, toggle it as shown on Figure 3-3.

The Debug area is split in two parts: the left part, called the Variables view, is where you can watch the values of variables: we will look at it later. The right part is Xcode’s console, which shows you two types of information: anything you choose to print out with the print function and messages from iOS about any runtime issues in your app. With the app running flick through the date picker to see the print messages pouring into the console.

Stepping Through Your Code

You can set a breakpoint in Xcode by single-clicking the gray strip to the left of a line of code. Clicking for a second time deactivates the breakpoint. If you want to delete a breakpoint, right-click it and select Delete breakpoint from the pop-up menu.

Let us set a breakpoint somewhere inside the getDayOfWeek function in ViewController.swift and run the app. As soon as the breakpoint is hit you can see several changes on the screen (Figure 3-4):

  • The Debugger controls appear at the top of the Debug area: use these to step over or into code, pause the execution, simulate location on the device, or move up and down the stack trace.

  • The Debug navigator is populated with information on the state of system resources, the state of the UI, and stack traces for each thread running in your app.

  • The Variables view contains variables you can inspect: you can switch between monitoring all variables and registers or only local variables, or let Xcode automatically choose what is available for inspection at a given breakpoint.

A371202_1_En_3_Fig4_HTML.jpg
Figure 3-4. Xcode’s screen gets updated with debug information when a breakpoint is hit

Click the Step over button in the Debugger controls strip or press F6 to step through your code. Use F8 to continue execution.

Watching Variables

With the debugger still paused at the breakpoint, have a look at the Variables view (Figure 3-4) and switch between the filters to see different sets of variables and registers reported: Auto, Local Variables, and All. Use the Debugger controls to step through your code and see the values change.

If you right-click inside the Variables view, you will be given the option to add values for inspection by selecting Add Expression… from the pop-up menu.

Executing Commands in the Console

The console allows you to type and execute commands at runtime. For example, you can manually output the value of a variable. Try this: type print weekDay in the console to get the value of the weekDay variable (Figure 3-5).

A371202_1_En_3_Fig5_HTML.jpg
Figure 3-5. You can manually call commands in the console to output values at runtime
Tip

We will look at console commands and their shortcuts in more detail in Chapter 8.

Changing a Value at Runtime

A useful command you can type in the console is expression (or expr for short). It lets you change the value of a variable at runtime: this way you can experiment and test different values without having to rebuild and restart your app. Let us try this: put a breakpoint at the line where we call print inside the updateDayOfWeek method (Figure 3-6). When the debugger stops at the breakpoint, type the following:

A371202_1_En_3_Fig6_HTML.jpg
Figure 3-6. Use the expression command to set an expression’s value at runtime
expression dayOfTheWeek.text = "day for coffee"

This will change the label’s text to “day for coffee.”

Warning

You may find that the expression command doesn’t always have an effect: Xcode sometimes optimizes where values are copied and read from, which gets in the way of changing them at runtime.

Inspecting Memory

You can see what an expression looks like in memory at a given point of the execution by right-clicking it in the Variables view and selecting View Memory of“nameOfTheExpression”.

Note

The View Memory of option may not always work for Swift data structures. This has been a known issue since Xcode 6. Apple suggests a workaround for this, which we will see how to implement in Chapter 8.

Let us see what the dateString variable looks like in memory. We declared dateString in the updateDayOfWeek method. Set a breakpoint at the line after the variable’s declaration and run the app in the debugger. When the breakpoint is hit, find dateString in the Variables view, right-click it, and select View Memory of “dateString” (Figure 3-7).

A371202_1_En_3_Fig7_HTML.jpg
Figure 3-7. You can see the memory layout of an expression in the Variables view

This will load the memory view in the Editor. If it looks like Figure 3-8, then you have nothing further to do: you can see the memory layout of dateString as hexadecimal numbers on the right and as characters on the left.

A371202_1_En_3_Fig8_HTML.jpg
Figure 3-8. Memory view

If, however, instead of lots of memory addresses and data you see a blank window and the address shown on top is 0x0, we will show you how to work around that when we get into more advanced debugging topics in Chapter 8 .

Summary

With Chapters 1 , 2 , and 3 in the bag you are now set to start implementing and testing apps for iOS with Xcode. In this chapter we covered the basic use of Xcode’s debugger—your best friend when it comes to making sure code does what you intend it to do. We saw how to manage breakpoints, how to step through code, and how to inspect and change runtime information.

Before we plunge into migrating your whole workflow to Xcode, we have a few more useful tools to show you in Chapter 4 , which will help you with further diagnosing your apps and with releasing them to the app store.

Footnotes

1 We actually used it already (sneakily): have another look at Listing 3-5.

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

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