iOS App Development For Dummies (2014)

Part III. Getting Your Feet Wet: Basic Functionality

image

image Visit www.dummies.com/extras/iosappdevelopment for more on how to develop your iOS app with storyboarding.

In this part …

·        Getting started with coding

·        Adding outlets and actions to your code

·        Adding animation and sound to your app

Chapter 8. It’s (Finally) Time to Code

In This Chapter

arrow Determining Internet availability

arrow Using the debugger

arrow Using breakpoints to examine runtime behavior

Yes, it’s finally time to start coding, although this chapter doesn’t get you going on the RoadTrip app functionality itself yet (the example app developed in this book). In this chapter, I show you some code you have to include to make sure that your app isn’t rejected out of hand by Apple.

Next, I give you an introduction to your new friend, the debugger. While some of you out there (but not me) may code perfectly, most developers make some mistakes as they develop an app. Fortunately, the debugger in Xcode starts helping you right from the start — so you want to understand how to use it as soon as you start coding.

Checking for Network Availability

One of the easiest ways to get your app rejected by Apple is to fail to make sure that you have an Internet connection when your app needs it, and therefore fail to notify the user that the functionality that requires the connection will be unavailable (or even worse, have your app just hang there).

Downloading the Reachability sample

Apple provides a sample app called Reachability that shows how to determine whether you have an Internet connection (as well as quite a bit of additional network information I won’t be going into), and you’ll be using that code in the RoadTrip app developed in this book. Here's how to use code from that valuable sample program:

1.     Download the Reachability sample from Apple by clicking Sample Code at http://developer.apple.com/devcenter/ios.

2.     Type Reachability in the Search field.

3.     Click the Reachability project in the search results, and in the iOS Developer Library window that appears, click the Download Sample Code button.

4.     In your Downloads folder, double-click the Reachability folder to open it.

You set your Safari Downloads folder in Safari⇒Preferences using the General tab.

5.     Open the inner Reachability folder and drag the Reachability.m and Reachability.h files into your project.

(I put them in my Supporting Files group just to keep them out of the way.)

6.     Select the check box in front of Road Trip in the Add to Targets section.

Be sure to select the Copy Items into destination group’s folder option (if it isn't already selected).

In order for you to be able to use this code, you need to add the SystemConfiguration framework. To do so, follow these steps:

1.     In the Project navigator, select the project icon (in this case, RoadTrip) at the top of the Project navigator content area to display the Project editor.

2.     In the targets pop-up menu just below the jump bar for the project, select RoadTrip.

3.     On the Build Phases tab, scroll down to the Link Binary with Libraries section.

4.     Expand the Link Binary with Libraries section if it isn't already expanded (see Figure 8-1) by clicking the disclosure triangle.

5.     Click the + (plus sign) button underneath the list of current project frameworks.

A list of frameworks appears.

6.     Scroll down and select SystemConfiguration.frameworkas shown in Figure 8-2.

7.     Click the Add button.

You’ll see the framework added to the Linked Frameworks and Libraries section.

8.     Close the Linked Frameworks and Libraries section.

image

Figure 8-1: Adding a framework.

image

Figure 8-2: Select 
the system 
configu­ration framework.

Adding the code to check for reachability

The place to check for whether you have access to the Internet is right when you start up. The method for doing that is the app delegate protocol method application:didFinishLaunchingWithOptions:.

You also need to include the Reachability.h file to be able to use Reachability, so add the bolded code in Listing 8-1 to the beginning of both the AppDelegate.m file and the application:didFinishLaunchingWith Options: method.

Listing 8-1: Updating the RTAppDelegate Implementation and application:didFinishLaunchingWithOptions:

  #import "AppDelegate.h"
#import "Reachability.h"

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application 
         didFinishLaunchingWithOptions:
                            (NSDictionary *)launchOptions
{
  if ([[UIDevice currentDevice] userInterfaceIdiom] == 
                                UIUserInterfaceIdiomPad) {
      UISplitViewController *splitViewController = (UISplitViewController *)
                           self.window.rootViewController;
      UINavigationController *navigationController = 
         [splitViewController.viewControllers lastObject];
      splitViewController.delegate =  
               (id)navigationController.topViewController;
  }
NetworkStatus networkStatus = 
  [[Reachability reachabilityForInternetConnection] 
                              currentReachabilityStatus];
  if (networkStatus == NotReachable) {
    UIAlertView *alert = [[UIAlertView alloc] 
       initWithTitle:@"Network Unavailable"
       message:@"RoadTrip requires an Internet connection" 
       delegate:nil
       cancelButtonTitle:@"OK" 
       otherButtonTitles:nil];
    [alert show];
  }
  return YES;
}

Ignore the code not in bold for the time being. I explain it in detail in Chapter 13.

In the main bolded section of Listing 8-1, you start by creating a Reachability object and then send it the currentReachabilityStatus message:

  NetworkStatus networkStatus = 
  [[Reachability reachabilityForInternetConnection] 
                               currentReachabilityStatus];

reachabilityForInternetConnection is an initializer that creates a Reachability object that checks for the availability of an Internet connection. As I said, Reachability has a lot of functionality, but all you really care about right now is whether you can reach the Internet.

Next, check to see whether you have network access:

  if (networkStatus == NotReachable) {

If you don’t have network access, you post an alert:

  UIAlertView *alert = [[UIAlertView alloc] 
      initWithTitle:@"Network Unavailable"
      message:@"RoadTrip requires an Internet connection" 
      delegate:nil
      cancelButtonTitle:@"OK" 
      otherButtonTitles:nil];
[alert show];

This is the standard way to configure and then show an alert. You have filled in the various (self-explanatory) parameters required by the initialization method. Configured this way, the alert will have a single button.

The show message to the alert object causes the alert to be displayed in the window, and when the user taps OK, the alert is dismissed.

image If you had added other buttons to give the user a choice of responses, you would have had to make the object posting the alert (the AppDelegate, in this case) a UIAlertViewDelegate, assigned the delegate parameter to self, and added the title of the other buttons using a nil terminated list. You would then have needed to implement the alertView:clickedButtonAtIndex: method in the delegate.

Explaining how Reachability works is beyond the scope of this book, but by examining the code, you can easily figure out how to get any other network status information you want.

If you run the app now, and either turn off your Internet connection on the computer (if you're running the Simulator) or turn on Airplane mode or turn off your Wi-Fi connection on the device, you see the message shown in Figure 8-3. (If this doesn’t seem to work, read on. What matters isn’t the behavior on the simulator but, later on, the behavior on a device.)

You can also temporarily change the

  if (networkStatus == NotReachable) {

to

  if (networkStatus != NotReachable) {

image

Figure 8-3: Checking the network connection.

so that the test works in reverse. Just be sure to change it back!

Of course, in a real app, you would want to do something further here, such as give the user options and so on. I’ll leave that up to you.

Congratulations! You’ve had your first adventure in coding land.

Exploring the Changes in iOS 7

iOS 7 introduces a major revision to the user interface of iOS. It addresses two main issues: the dated look of the interface and the fact that content was getting lost on the app screen.

The dated interface

Change for the sake of change may or may not be a good idea — it depends on the context and the cost. In the case of a new user interface, users and developers have to learn new skills.

With iOS 7, the functionality of the interface changes very little. Apple was able to make relatively small changes in the interface appearance, and for most users, not much changed. Developers have a few extra items to think about.

The “datedness” of the interface wasn’t so much the fact that it had been around for a while, but that it was designed originally for the iPhone with a small screen and a much less powerful processor than we have today. The screen on the iPhone is larger today, and its resolution is much higher with the Retina display. The iPad, of course, is the same size (although the iPad Mini came along a little while ago), but both are now sporting Retina displays.

This means that not only is there more screen real estate to use, but the details can be much smaller and subtler. In demonstrations of the Retina display, we usually see beautiful photos. However, the fact that very small elements on the screen can now be visible does have an effect on the user interface.

This has all happened before. If you look at screenshots of the original Mac (or a PC), you’ll see interfaces that look very old and clunky. We just don’t use those enormous interface elements any more the way we had to a couple of decades ago. It’s also important to note that Apple has significant tools in the accessibility area so that, even with small interface elements, people with limited vision can still use the devices.

Losing the content

The second issue that the interface revision addressed was the fact that content was sometimes getting lost on the screen. At the Worldwide Developers Conference in June 2013 where iOS 7 was first demonstrated, speaker after speaker stressed that part of the design goal was to make the content stand out and the interface disappear as much as possible.

Part of the strategy to make the content stand out was to simplify the user interface. One important simplification is to introduce the idea of a tint color (really a highlight color). If you set a tint color for your app, the interface is drawn basically in gray on a white background with the exception of items that are highlighted: All highlighted items use the tint color. You can set it for your app or for an individual window. Users may not even notice the fact that all highlights appear in the same color unless you point it out to them, but it makes learning how to use the app and — most importantly — distinguishing between content and interface much easier.

If your app uses color in its content, a good tint color is one that is unlikely to show up in the content, if that’s possible. Remember, the point of the tint color is to distinguish the interface from the content. A secondary point is to remind users what app they’re in. Apple, for example, uses blue as the tint color in many of the built-in apps. You’re welcome to use it, but if you choose a different color (a significantly different color) you can help people know where they are.

Furthermore, if the tint color picks up a color from your app icon, you also may establish your own palette identity. You can set a tint color for an individual window, but many apps set it globally. To do so, select a storyboard file from in the Project navigator and use the File inspector to set the tint color, as shown in Figure 8-4. This method makes it easy to use different tint colors for each storyboard. So that means you can set the tint color dynamically in code for a window regardless of device, for a storyboard and all of its views and view controllers, or for a specific view (that, too, would require code).

image

Figure 8-4: Set the tint color.

Setting the Master View Controller Title

You’ll also want to be able to set the title in the Navigation bar for the view. You could have done that in Interface Builder, but I’m showing you how to do it programmatically because you want to be able to set the title of the view based on where the user is going.

To set the MasterViewController title, add the bolded code in Listing 8-2 to viewDidLoad in MasterViewController.m.

Listing 8-2: Updating viewDidLoad

  - (void)viewDidLoad
{
  [super viewDidLoad];
  // Do any additional setup after loading the view,
     typically from a nib.
  self.detailViewController = 
    (DetailViewController *)
    [[self.splitViewController.viewControllers 
      lastObject] topViewController];
  self.title = @"Road Trip";
}

How did I know to put this code here, rather than in some other section of the code? viewDidLoad is the message sent when the view is loaded for the first time, but before it's displayed. If you want a title, you want to set it here, before the view is displayed.

Understanding Autorotation

One of the responsibilities of the UIViewController class is to work with the app’s window to handle device rotation (also known as device orientation changes). Although the UIViewController class itself already includes the functionality to animate the transition from the current orientation to the new one (which you can override if you need to lay out the view again for the new orientation), it must also communicate to the application window whether it in fact wants to support a particular orientation.

In earlier versions of iOS, you had to override certain UIViewController methods to control autorotation, but you can manage this now by simply choosing your desired Device Orientations in the Target’s Deployment Info section of the General tab, as shown in Figure 8-5.

image

Figure 8-5: The Target’s Supported Device Orientations.

Writing Bug-Free Code

Although some developers think that writing code is where they spend the vast majority of their time when they're developing an app, debugging is actually right up there as a very close second. (And yes, I know that the title of this section is wishful thinking.)

Because debugging plays such a crucial role in writing workable code, I want to use this section to emphasize two points:

·        App developers should strive to write code with as few bugs as possible (duh!).

·        App developers need to know how to use the debugger so they can track down the inevitable bugs they do introduce into their code as efficiently as possible.

With the release of Xcode 5, Apple has made it easier to write code with fewer bugs, as well as use the debugger to track down bugs you do have.

Because the best defense is a good offense, I want to start with the tools that Xcode provides that help you to write less buggy code. Xcode has figured out that the best way to make sure your code has as few bugs as possible is by giving you the opportunity to fix the code as you write it. Such opportunities come in the form of Xcode’s various compiler warnings. More specifically, by taking advantage of the Live Issues and Fix-it features, which I explain in Chapter 7, you’ll catch many of your errors before you even run your app, and fixing them will be easy. (Well, some of them, at least.) Live Issues continuously evaluates your code in the background and alerts you to coding mistakes, and Fix-it will also offer to fix the problem for you. I suggest that unless you are crystal clear about what you're doing, don’t run your app without first resolving any outstanding compiler warnings.

Although Live Issues and Fix-it can catch many problems and help you resolve them, they can’t identify and fix everything. (I can tell you that they have made my life more difficult. When I want to demonstrate how to fix a coding error in a book or class, it’s much harder to set it up because Live Issues and Fix-it tend to catch the error before I can finish typing it.)

Working in the Debug area and Debug navigator

The Debug area consists of the Debug bar, partnered with the Variables pane and the Console pane, each of which has a Scope bar fitted out with a pop-up menu. You usually use the Debug area in conjunction with the Debug navigator.

You access the Debug area by selecting it in the Xcode toolbar’s View selector (as shown in Figure 8-6). You select the Debug navigator by showing the Navigator area and then selecting the Debug navigator in the Navigator selector bar. The default behavior is to show the Debug navigator and the relevant debugging gauges (you can change this in Debug preferences).

If you get a runtime error (or if you click the Pause button or a breakpoint is triggered), the Debug area and the Debug navigator open automatically.

Figure 8-7 show what happens when you hit a breakpoint (which I explain shortly) in your program.

What you see in the Debug area is controlled by using the Debug area Scope buttons, shown in Figure 8-8 at the bottom right of the Debug area. You use this bar to toggle between the Variables pane only (left button), both Variables and Console panes (both buttons), and Console pane only (right button).

image

Figure 8-6: Accessing the Debug area.

image

Figure 8-7: Hitting a breakpoint displays the Debug area and Debug navigator.

image

Figure 8-8: Use the Debug area Scope buttons to control what panes you see in the Debug area.

The Variables pane and the Console pane have their very own Scope bars as well. The pop-up menu in the Variables pane Scope bar lets you display

·        Auto: Recently accessed variables

·        Local: Local variables

·        All: All variables and registers

The pop-up menu in the Console pane Scope bar lets you display

·        All Output: Target and debugger output

·        Debugger Output: Debugger output only

·        Target Output: Target output (program logging to the debugger, for example) only

image Xcode offers other controls and filters for what gets displayed that I encourage you to explore on your own.

Managing breakpoints

You can use the debugger to pause execution of your program at any time and view the state of the running code.

As mentioned previously, you won’t find much to see in the Debug area and Debug navigator unless your program is stopped at a breakpoint or paused (and not much at those points, either). The debugger is more useful to you if you set breakpoints to stop at known points and then view the values of the variables in your source code. Given that fact, it’s probably time to show you how to set a breakpoint and explain what a breakpoint is.

breakpoint is an instruction to the debugger to stop execution at a particular program instruction. By setting breakpoints at various methods in your program, you can step through its execution — at the instruction level — to see exactly what it’s doing. You can also examine the variables that the program is setting and using. If you’re stymied by a logic error, setting breakpoints is a great way to break that logjam.

To set breakpoints, open a file in the Source editor and click in the Gutter — the column between the Navigator area and the Focus ribbon that is adjacent to the Editor area in Figure 8-8 — next to the spot where you want execution to stop. You can toggle the state (on or off) of all the breakpoints in your program at any time by clicking the Breakpoints button at the left of the Debug bar: it's the colored button that's the second from the left. In Figure 8-8, note that the button looks like the breakpoint that's set in the gutter next to UINavigationController.

image To disable an individual breakpoint, click its icon in the gutter. To get rid of a breakpoint completely, simply drag it off to the side. You can also right-click (or Control-click) the breakpoint and choose Delete Breakpoint from the pop-up menu that appears.

image In Figure 8-9, I've added a breakpoint to the statement just before I check to see if the device is an iPad. You’ll also notice that I’ve displayed the Breakpoint navigator by selecting the appropriate icon in the Navigator selector bar. The Breakpoint navigator lets you see all breakpoints at once; if you select a given breakpoint in the Breakpoint navigator, it displays in the Source editor (where you can also edit it).

image You can set several options for each breakpoint by Control-clicking the breakpoint and choosing Edit Breakpoint from the shortcut menu that appears, as shown in Figure 8-10.

image

Figure 8-9: Setting a breakpoint and displaying the Breakpoint navigator.

image

Figure 8-10: Editing a breakpoint.

Doing so opens the Edit Breakpoint window, where you can set the actions and options you want for breakpoints added in the Breakpoint editor. As shown in Figure 8-11, you can set a condition for a breakpoint, ignore it a set number of times before stopping, add an action, and automatically continue after evaluating actions.

In Figure 8-11, I selected the Add Action button and then chose to add a sound in Figure 8-12. I also set a condition that I want the breakpoint to be triggered only if the networkStatus isn't equal to notReachable. In this case, as you can see in Figure 8-12, I had to specify

  networkStatus != 0

This is because networkStatus is not a symbol the debugger has access to, but rather an enumerated type (a set of named values that behave as constants). If you examine the Reachability.h file, you’ll find

  typedef enum {
          NotReachable = 0,
          ReachableViaWiFi,
          ReachableViaWWAN
} NetworkStatus;

image

Figure 8-11: Some breakpoint options.

image

Figure 8-12: Fine-tuning the breakpoint.

The “normal” condition, of course, would be to set the breakpoint to stop when the condition is something you don’t expect, like the networkStatus equal toNotReachable. But I want to keep my Mac connected to my network (which connects the Simulator as well), so I set the breakpoint condition to be equal to Not Reachable so it would stop at the breakpoint every time (unless of course my network unexpectedly goes down).

Set this breakpoint and run your program in Xcode. As you saw previously in Figure 8-7, you’ll be stopped at the breakpoint.

As you can see in the figure, when the breakpoint is reached, the Debug area is displayed and the Debug navigator opened automatically. (You can change that response in the Behaviors tab of Xcode Preferences.) It stopped because the condition I set (networkStatus != 0) evaluated YES.

What you’ll find in the Debug area

On one side of the Debug area you have the Variables pane (which displays the values of variables), and on the other side, you have the Console pane. You select one or both with the Debug area Scope buttons at the lower right of the Debug area. In Figure 8-7, for example, you saw only the Variables pane.

The Variables pane

The Variables pane displays the variables you’re interested in. Click the disclosure triangle next to self to see the instance variables in the object. You’ll see the local variables to a method as well. As mentioned earlier, you can specify which items to display by using the pop-up menu in the top-left corner of the Variables pane:

·        Auto: Displays only the variables you’re most likely to be interested in, given the current context

·        Local: Displays local variables

·        All: Displays all variables and registers

You can also use the Search field on the toolbar to filter the items displayed in the Variables pane.

The Console pane

The Console pane displays program output. Again, as mentioned earlier, you can specify the type of output you see in the console by using the pop-up menu in the top-left corner of the Console pane:

·        All Output: Displays target and debugger output

·        Debugger Output: Displays debugger output only

·        Target Output: Displays target output only

When you are stopped at the breakpoint you set earlier, what you see is a lot of boilerplate and then this:

  2012-02-19 12:02:12.486 RoadTrip[26123:f803] Reachability Flag Status: -R -----l- networkStatusForFlags
(lldb)

Not much of interest here, but in Chapter 11, you’ll find out how to print (really display) the contents of a variable to the Console pane — and in Chapter 15, you’ll have the opportunity to examine some runtime error messages.

The (rather boring) stuff you see here is the result of an NSLog statement in Reachability:

  2012-02-19 12:02:12.486 RoadTrip[26123:f803] Reachability  
             Flag Status: -R -----l- networkStatusForFlags

NSLog allows you to display information in the Console pane during execution. For example, if you wanted to know how many points of interest your app had to display (the number of elements in the poiData array — you find out about poiData in Chapter 17), instead of using a breakpoint and displaying a variable, you could add the following NSLog statement:

  NSLog(@"Number of points of interest %i", 
                                         [poiData count]);

which would display

  2012-02-19 12:06:52.688 RoadTrip[26145:f803] 
                            Number of points of interest 1

in the Console pane.

NSLog is pretty useful and uses the same formatting as NSString’s stringWithFormat and other formatting methods.

What you’ll find in the Debug navigator

image Selecting an item in the Debug navigator causes information about the item to be displayed in the Source editor. For example, selecting a method displays the source code for that function in the Source editor.

Each app within iOS is made up of one or more threads, each of which represents a single path of execution through the app's code. Every app starts with a single thread, which runs the app's main function. The main thread encompasses the app’s main run loop, and it’s where theNSApplication object receives events. Apps can add (spawn) additional threads, each of which executes the code of a specific method.

image Threads per se are way beyond the scope of this book, but that’s okay: Here you’ll be concerned with only the main thread.

Every time you send a message (or make a function call), the debugger stores information about it in a stack frame and then it stores all such frames in the call stack. When you’re thrown into the debugger because of an error (or if you pause the application by clicking the Pause button on the toolbar), Xcode displays the thread list, and within each thread the call stack for that thread, putting the most recent call at the top. The call stack shows a trace of the objects and methods that got you to where you are now.

You can do a lot more as far as threads are concerned, but again, that’s outside of the scope of this book. (If you don’t know whether to be disappointed or relieved, hold that thought.)

image Although the trace isn’t really all that useful in this particular context, it can be very useful in a more complex application — it can help you to understand the path that you took to get where you are. Seeing how one object sent a message to another object — which sent a message to a third object — can be really helpful, especially if you didn’t expect the program flow to work that way.

Getting a look at the call stack can also be useful if you’re trying to understand how the framework does its job, and in what order messages are sent. As you’ll soon see, you can stop the execution of your program at a breakpoint and trace the messages sent up to that point.

Displaying variables in the Source editor

In the Debugger window, you can move your pointer over an object or variable in the Source editor to show its contents and move your pointer over disclosure triangles to see even more information when the app is stopped at a breakpoint.

In Figure 8-13, for example, I moved the pointer over navigationController to see its value (information about the current status of the Internet connection).

image When you move your pointer over a variable, its contents are revealed — and if more disclosure triangles appear, you can move your pointer over them to see even more information (which I explain in more detail in Chapter 11).

You see the value of the variable in the Variables pane as well.

In the next section, I show you how to step through your program after it’s stopped at a breakpoint.

image

Figure 8-13: Showing the navigation
controller.

Tiptoeing through your program

When you build and run the program with breakpoints, the Debug bar appears in the Workspace window as the program runs in the Simulator. The program stops executing at the first breakpoint (if you have set a condition, it stops executing if that condition is met).

To control the execution, you use the Debug bar (located at the top of the Debug area that you see in Figure 8-14). The Debug bar includes buttons to

·        Open or close the Debug area. As mentioned previously, you can hide the Debug area if you don’t need it for what you’re doing right now.

·        Turn all breakpoints on or off. This will let you keep them in place for whenever you need to debug them again.

·        Pause or resume execution of your code. Click this button to stop your program from executing or continue execution after it stopped when it entered the debugger.

·        Step over. Click this button to make the process counter (PC), which is identified by the green arrow in the gutter, move to the next line of code to be executed. If that line of code sends a message, it will send the message (and run the method) — but then, from your perspective, it just moves to the next line of code.

image

Figure 8-14: The Debug area and Debug bar.

·        Step in. Click this button to move the process counter to the next line of code to be executed. If the line of code sends a message to a method in your source code, the debugger will step to the method and then return to the next line of code after the line that sends the message.

·        Step out. Click this button to step out of the current function or method. The Source editor then displays either the method that sent the message or the function’s caller.

·        Simulate location. You can have the debugger simulate the location of the iPad for you. I explain this in Chapter 17.

When I build and run RoadTrip in Figure 8-14, you can see that the program has stopped executing at the breakpoint. If I then want to watch what happens as RoadTrip executes step-by-step, I would select Step In and proceed line by line. At each line, I can view the values of the variables as they change (changed values are shown in blue). When I have seen what I want to see, I can resume execution or stop the app and make my repairs.

This concludes your introduction to the debugger and Debug navigator. I do want to show you a couple more things, but I need to have you add more code to have them make sense. In Chapter 11, I show you how to print (display) the contents of a variable in the Console pane, and then in Chapter 15, I show you a couple of my favorite runtime errors.