Intermediate Debugging with Xcode 4.5
This is a tutorial for intermediate iOS developers, where you’ll get hands-on experience with some extremely useful debugging techniques. By Brian Moakley.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Sounding Out Your Save Methods
At this point, you should have plenty of data in the app. It’s time to save it all. With apps like this, saving should be done frequently so that nothing is lost. That’s not the case with this app. It only saves when the user exits the application.
Click Back on the navbar to return to the root view controller, then simulate a home button press. You can do this from the Simulator’s menu by selecting Hardware\Home or by pressing shift-command-h.
Now stop the program from Xcode, and build and run. The tableview is empty. The app failed to save anything.
Open AppDelegate.m. In the applicationDidEnterBackground method, you should see the problem at once. There is a method called doLotsOfWork. The work isn’t being finished in time, so iOS is terminating your app before it finishes its cleanup. The result of this early termination is that the saveData method is not being called.
Let’s make sure that data is saved first. In the applicationDidEnterBackground, move the [[DataStore sharedDataStore] saveData]; method above the doLotsOfWork method like so:
[[DataStore sharedDataStore] saveData];<br />[self doLotsOfWork]; |
[[DataStore sharedDataStore] saveData];<br />[self doLotsOfWork];
Now, add a breakpoint on the doLotsOfWork line. Right click or control click the breakpoint and select ‘Edit Breakpoint’. Select a sound action and choose “Submarine” as the sound. When dealing with sound actions, I try to avoid system sounds as I may easily overlook them.
Next, click the checkbox next to “Automatically continue after evaluating”. Finally, click build and run.
When the app starts again, add a new user then press the home button in the simulator. Just after the app closes, you should hear the submarine sound, indicating that the data has been saved.
Stop the app in Xcode, then press Run. You should see the data in all its glory.
Playing a sound is a good way to know if a certain code path has been reached without having to look through the logs. You can also provide your own custom sounds in case you want to play an explosion for a particular bad crash.
To do so, just drop your sound files in this folder:
YOUR_HOME_DIRECTORY/Library/Sounds
You’ll have to restart Xcode before you can use them, but think of all the potential shenanigans :]
Conditions for Successful Debugging
There are times in development when it is necessary to change the state of your program at certain intervals. Sometimes these changes occur in the middle of large sequences of events which makes normal debugging quite difficult. That’s where conditions come into play.
Now that you have some friends listed in the app, tap one of their names in the root view controller to bring up the gift interface. It’s just a simple grouped table that can be sorted on whether the gift can be purchased or not.
Press the add button on the navigation bar to add a new item. For the name, put shoes. For the price, put 88.00. Tap the OK button. The shoes should now appear on in the gift table.
Now add the following items:
Sleigh / 540.00
Candles / 1.99
XBox / 299.99
iPad / 499.99
Yikes. You realized that you actually wanted to record a PS3 instead of an XBox. You could simply tap the cell to edit it, but for the sake of demonstration, you will edit it through the debugger.
Open up GiftListsViewController.m and look for the method cellForRowAtIndexPath. Add a breakpoint on the line underneath the code that reads:
<span style="color: #002200;">if (gift) {</span> |
<span style="color: #002200;">if (gift) {</span>
Now right click or control click the breakpoint, and select ‘Edit Breakpoint’.
It’s time to put your condition. Think of this like a simple if statement. Add the following code:
(BOOL) [gift.name isEqualToString:@"XBox"]
LLDB requires us to provide a cast which is why you have the BOOL before the expression. Click done.
Now, press the Bought segmented control button. The table reloads new data but the breakpoint does not trip.
Press the Saved segmented control button. This time everything should pause with the highlighted item selected in the debugger console.
In the debugger console, add the following:
<span style="color: #7a0874; font-weight: bold;">(</span>lldb<span style="color: #7a0874; font-weight: bold;">)</span> expr (void) [gift setName:@"PS3"] |
<span style="color: #7a0874; font-weight: bold;">(</span>lldb<span style="color: #7a0874; font-weight: bold;">)</span> expr (void) [gift setName:@"PS3"]
Now, press the play button and the table will continue to load. The PS3 replaces the XBox in the gift results.
This same results can accomplished by setting the number of iterations. Control click or right click the break point, and select ‘Delete Breakpoint’. Xcode can get a little wonky when editing conditions. It is best to start with a clean slate. Add a new breakpoint in the same place. This time, in the ignore text field, select the number 3. Click done.
Now press the Bought segmented control then the Saved segmented control.
We should hit the same breakpoint. To confirm that you are at the correct object, type:
<span style="color: #7a0874; font-weight: bold;">(</span>lldb<span style="color: #7a0874; font-weight: bold;">)</span> po gift |
<span style="color: #7a0874; font-weight: bold;">(</span>lldb<span style="color: #7a0874; font-weight: bold;">)</span> po gift
Now revert the object back to its previous state:
<span style="color: #7a0874; font-weight: bold;">(</span>lldb<span style="color: #7a0874; font-weight: bold;">)</span> (void)[gift setName:@"XBox 360"] |
<span style="color: #7a0874; font-weight: bold;">(</span>lldb<span style="color: #7a0874; font-weight: bold;">)</span> (void)[gift setName:@"XBox 360"]
The table should now reflect the update. Isn’t real time editing just great?
Starting up by Tearing Down
When developing data driven apps, often times, it is important to wipe the data store clean. There are a number of ways of doing this from reseting the iPhone simulator to locating the actual datastore on your computer and deleting it. Doing this over and over can be a bit tedious, so get a little lazy and have Xcode do it for us.
We’ll start by creating a shell script. A shell script is a list of commands that automate some actions of the operating system. To create a shell script, create a new file from the application menu. Click File\New\File or command-n. From the category listings, select Other and then select Shell Script as the type.
For the name, put wipe-db.sh
Now you have to find the actual data store. Open up the terminal is located. If you don’t know where the terminal is located, you can find it in your Application folder inside of the Utilities folder.
Once the terminal has started, change your location to your home directory by entering the following:
YourComputer$ <span style="color: #007800;">cd ~</span> |
YourComputer$ <span style="color: #007800;">cd ~</span>
Next list out the directory contents by entering:
YourComputer$ <span style="color: #007800;">ls</span> |
YourComputer$ <span style="color: #007800;">ls</span>
Give the directory listing a good look over. If you do not see a folder labeled Library, enter the following command:
YourComputer$ <span style="color: #007800;">chflags nohidden ~/Library/</span> |
YourComputer$ <span style="color: #007800;">chflags nohidden ~/Library/</span>
Then restart the terminal.
Now, move to the folder containing the iPhone simulator by entering the command:
YourComputer$ <span style="color: #007800;">cd ~/Library/Application\ Support/iPhone\ Simulator/6.0/Applications</span> |
YourComputer$ <span style="color: #007800;">cd ~/Library/Application\ Support/iPhone\ Simulator/6.0/Applications</span>
List out the directories by typing:
YourComputer$ <span style="color: #007800;">ls</span> |
YourComputer$ <span style="color: #007800;">ls</span>
You may see a lot of different directories, depending on how many apps you currently have installed in simulator. You need to find the folder for GiftLister so it may take some trial and error. To enter a folder, you will need type: cd THE_NAME_OF_YOUR_FOLDER
To save some time, only type in the first three letters of the folder’s name, then press tab. The terminal will autocomplete the folder for you. If not, keep typing letters until it does. In my case, I have the folder: 0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9 so I would type
YourComputer$ <span style="color: #007800;">cd 0B1</span> |
YourComputer$ <span style="color: #007800;">cd 0B1</span>
Then I would press tab.
Once inside you should see the file: GiftLister.app. If not, try another folder. Also, this project is based on iOS 6. If you are using an earlier simulator, then enter the following:
YourComputer$ <span style="color: #007800;">cd ~/Library/Application\ Support/iPhone\ Simulator/</span> |
YourComputer$ <span style="color: #007800;">cd ~/Library/Application\ Support/iPhone\ Simulator/</span>
Then type ls to display the contents. Choose the correct simulator version, and enter the directory by typing: cd VERSION_NUMBER/Applications (for example, cd 6.0/Applications
Once you have found your application folder, enter the following:
YourComputer$ <span style="color: #007800;">cd Library</span> |
YourComputer$ <span style="color: #007800;">cd Library</span>
Now list the directory contents by typing:
YourComputer$ <span style="color: #007800;">ls</span> |
YourComputer$ <span style="color: #007800;">ls</span>
You should see the file giftlister.sqlite. Jackpot.
Now print out the path to the file by typing the following:
YourComputer$ <span style="color: #007800;">pwd</span> |
YourComputer$ <span style="color: #007800;">pwd</span>
Copy the full path of the file and paste it into the shell script. At the end of the path, add the following:
/giftlister.sqlite |
/giftlister.sqlite
Your full path should look something like this:
/Users/Brian/Library/Application Support/iPhone Simulator/6.0/Applications/0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9/Library/giftlister.sqlite |
/Users/Brian/Library/Application Support/iPhone Simulator/6.0/Applications/0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9/Library/giftlister.sqlite
Unfortunately, you can’t have spaces in the path so you need to transform these words:
/iPhone Simulator/<br/>/Application Support/ |
/iPhone Simulator/<br/>/Application Support/
to look like this:
/iPhone\ Simulator/<br/>/Application\ Support/ |
/iPhone\ Simulator/<br/>/Application\ Support/
The completed path should look like the following:
/Users/Brian/Library/Application\ Support/iPhone\ Simulator/6.0/Applications/0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9/Library/giftlister.sqlite |
/Users/Brian/Library/Application\ Support/iPhone\ Simulator/6.0/Applications/0B1E5AD3-7292-45A6-BB5D-F1C004AC47F9/Library/giftlister.sqlite
Preceding the path, add the remove command which is simply rm. The line should look like:
YourComputer$ <span style="color: #007800;">ls</span> |
YourComputer$ <span style="color: #007800;">ls</span>
Here’s what the completed shell script will look like:
Save the shell script and close it.
By default, shell scripts are read only. you need to make this one executable. With the terminal open, return to your home directory by entering the following:
YourComputer$ <span style="color: #007800;">cd ~</span> |
YourComputer$ <span style="color: #007800;">cd ~</span>
Now, list the contents of the directory by typing:
YourComputer$ <span style="color: #007800;">ls</span> |
YourComputer$ <span style="color: #007800;">ls</span>
You will have to navigate to the location of your project folder. If you placed it on your desktop, you would navigate to it by typing:
YourComputer$ <span style="color:#007800;">cd Desktop</span><br> <span style="color: #100;">YourComputer$ <span style="color:#007800;">cd GiftLister</span> |
YourComputer$ <span style="color:#007800;">cd Desktop</span><br> <span style="color: #100;">YourComputer$ <span style="color:#007800;">cd GiftLister</span>
If you have to navigate up a directory, type the following:
YourComputer$ <span style="color: #007800;">cd ..</span> |
YourComputer$ <span style="color: #007800;">cd ..</span>
After a long crawl through the terminal, you should see all the project files. To make the shell script executable, type the following:
YourComputer$ <span style="color: #007800;">chmod a+x wipe-db.sh</span> |
YourComputer$ <span style="color: #007800;">chmod a+x wipe-db.sh</span>
Chmod is a program that changes the permissions of a file. The a+x allows the file to be executable for all users, groups, and others.
Wow … that was a lot. Take a breather. You deserve it. Sometime being lazy can take a lot of work.
Close the terminal and return to Xcode. Open AppDelegate.m. Set a breakpoint on the first line of the method didFinishLaunchingWithOptions. Right click or control click the breakpoint and select ‘Edit Breakpoint’. Add an action and select ‘Shell Command’. In the next dialog, press the Choose button and select the shell script that you just created. Click the “Automatically continue after evaluating” checkbox, then press done.
Stop the simulator if it is running. Now build and run. The database is now deleted.
The simulator tends to cache a lot of data, so I find the best thing to do is a clean build by pressing Clean from Xcode’s product menu, then build and run. Otherwise, you can run the app, stop it, then run it again. The cached data will be gone with a brand spanking new database.
While it did take some bit of work to setup, now clearing out the database can be preformed with the press of a button. When not in use, simply disable the breakpoint.
Note: You just created a shell script and wrote a simple Unix command to delete the file. You can just as easily have loaded a PHP file within the shell script to do the same thing. You could also launch a Java program, python script, or any other program on the machine. The key point, you don’t need to learn shell scripting to manipulate the underlying operating system through a breakpoint.
Note: You just created a shell script and wrote a simple Unix command to delete the file. You can just as easily have loaded a PHP file within the shell script to do the same thing. You could also launch a Java program, python script, or any other program on the machine. The key point, you don’t need to learn shell scripting to manipulate the underlying operating system through a breakpoint.