| Erica Sadun Published by Addison-Wesley Professional ISBN-10: 0-321-75426-3 ISBN-13: 978-0-321-75426-4 |
Xcode
helps you craft iOS SDK applications with an exciting suite of code editors and
testing tools. This chapter introduces you to the basics of using Xcode to
build your projects. You see how to build a simple Hello World project, compile
and test it in the simulator, and then learn how to compile for and deploy to
the device. You also discover some basic debugging tools and walk through their
use as well as pick up some tips about handy compiler directives. This chapter
also looks at how to submit to the App Store and perform ad hoc distribution
for testing. By the time you finish this chapter, you’ll have followed the
application-creation progress from start to finish and been shown valuable
tricks along the way.
Creating
New Projects
If
diving into SDK programming without a lifeline seems daunting, be reassured.
Xcode simplifies the process of getting started. It provides preconfigured
projects that you can easily adapt while exploring the SDK. These projects
provide fully working skeletons. All you need to do is add a little custom
functionality to make that app your own.
To
get started, launch Xcode 4 and choose File > New Project (Command-Shift-N).
The New Project template window (see Figure 3-1)
opens, allowing you to select one of these application styles to get started.
These project styles are chosen to match the most common development patterns
for iOS. Your choices are as follows:
Figure 3-1
The Xcode New Project template selection window. The Xcode interface will
change as Apple continues evolving its design tools.
- Document-Based
Application—Intended for use with iCloud, the document template
creates a starting point for building applications around ubiquitous elements.
- Master-Detail
Application—Usually based around lists and tables, master-detail
applications let users drill their way through a hierarchical interface. These
apps offer a tree-structured collection of interface choices, each choice
sliding to a new screen or presenting, in the case of the iPad, in a separate
detail view. The bars at the top of the navigation screens include an
integrated Back button, letting users return to previous screens with a single
tap. On the iPad, split views automatically accommodate themselves to match device
orientations. In landscape mode, both views are shown at once; in portrait, the
detail view is shown and the selection choices appear in via a
navigation-bar-based popover.
- OpenGL
Game—When
programming with OpenGL ES, all you need is a view to draw into and a timer
that offers an animation heartbeat. The OpenGL Game template provides these
elements, letting you build your OpenGL ES graphics on top.
- Page-Based
Application—Create a book-style application by choosing this page
view controller-based template. New to iOS 5, the page view controller allows
users to navigate through an electronic “book” using familiar touch-based
gestures. The data source client feeds view controllers to the application, and
a delegate allows the app to respond to gesture-based navigation and
orientation updates.
- Single
View Application—This simple template provides a basic
starting point for a primary view controller, offering storyboards for both
iPhone and iPad distribution. Choose this style when you’re looking for an app
that centers on a primary view rather than one that needs a specialized
container style, such as a navigation controller, tab bar controller, split
view controller, page view controller, and so on.
- Tabbed
Application—Apple’s iPod and YouTube applications offer typical
examples of tab bar applications. In these applications, users can choose from
a series of parallel screens by tapping buttons in a bar at the bottom of the
application. For example, the YouTube application lets you choose from Featured
Videos, Most Viewed, Bookmarks, and the search pane, each of which is accessed
through a tab button. The Tabbed Application template provides a skeleton that
you can grow to add panes and their contents. Although you can select either
the iPhone or iPad as your target product in Xcode, Apple encourages you to
avoid creating tab-bar-style applications on the iPad. The iPad’s generous
screen space provides enough room that you do not need to fold your main
interfaces using the conventions of tab bar and navigation applications.
- Utility
Application—Meant to be the simplest style of application, the
Utility Application template creates a two-sided single-view presentation like
the ones you see in the Stocks and Weather application. The template provides a
main view and a flip view, which you can easily customize. This application
template uses a simple flip-to-the-other-side presentation on the iPhone. On
the iPad, it offers a popover linked to an information bar button item. Utility
applications work best when they are highly focused. The flip-view or popover
generally serves for in-app settings rather than an extension of the primary
interface feature set.
- Empty
Application—The window-based application essentially offers the same
template as the Single View one but without the storyboards. You get an
application delegate and a customizable window, and that’s about it. One
advantage of choosing this template is that it’s relatively easy to customize
if you prefer to build your iPhone applications completely from scratch.
Note
-
Apple offers sample code and tutorials at the iOS Reference Library. Visit the
library online at
http://developer.apple.com/library/ios/navigation/index.html;
you must use your developer credentials to access its contents. In addition to
sample code, you’ll find release notes, technical notes, Getting Started
guides, Coding How-To’s, and more. Many of these resources are also available
directly in Xcode through its built-in documentation browser.
Building
Hello World the Template Way
Xcode’s
preconfigured templates offer the easiest path to creating a Hello World–style
sample application. In the following steps, you create a new project, edit it
to say “Hello World,” and run it on the iOS simulator. As you build your first
Xcode project, you’ll discover some of the key development pathways.
Create
a New Project
With
the iOS SDK installed, launch Xcode. Close the Xcode Welcome page; it’s the
window that says “Welcome to Xcode” and offers options such as Create a New
Xcode Project. This window continues to appear until you uncheck “Show this
window when Xcode launches” before closing it. Thereafter, you can access the
page via Window > Welcome to Xcode (Command-Shift-1).
To
create a new project, choose File > New > New Project (Command-Shift-N).
This opens the template selection window shown in Figure
3-1. By default, the template selection window is embedded in a large new
window, which is called a “workspace.” Workspaces embed all of Xcode’s editing
and inspector features into a single window.
The
left column in Figure 3-1 includes three
iPhone project categories. These are Application (that is, the screen you see
in Figure 3-1) Framework & Library (for
creating static Cocoa Touch library modules), and Other (which initially
contains a single, empty project style).
Choose
Application > Single View Application and then click Next. Xcode opens a
“Choose options for your new project:” screen, as shown in Figure 3-2. Enter Hello World
for the project name and set the company identifier (for example, com.sadun).
Company identifiers typically use reverse domain naming. The new application
identifier appears below this in light grey text. In my case, this is
com.sadun.Hello-World. Enter an optional class prefix. Xcode uses this to
prepend template classes. If you enter ES, for example, Xcode creates
ESAppDelegate.h and .m files. Choose Universal from the Device Family pop-up.
Leave Use Storyboard checked. Leave Include Unit Tests unchecked. Click Next.
Figure 3-2
Once you set your company identifier, Xcode applies your settings between
successive runs. This helps you avoid what was one of the most irritating
features of previous Xcode releases—having to remember to edit your settings
from “com.yourcompany” for each project.
Choose
where to save the new project (such as the desktop) and click Save. A new Hello
World Xcode workspace opens (see Figure 3-3).
This project contains all the files needed to design a new, universal
application centered on a single primary window. The files are grouped together
into folders and listed in the left-hand pane, which is called the Navigator.
Your new project is selected by default. Its project and target settings appear
in the right-hand editor pane. This project settings editor is functionally
similar to the target info pane found in earlier Xcode releases but with many
improved features. The first editor pane you see allows you to choose
orientation support and set application images.
Figure 3-3
This brand-new Hello World project was created by choosing one of the available
templates. On older projects, you may see a “modernize” button on this screen
as well.
Feel
free to explore the files in your new project. Open groups (they look like
folders but are just organizing aids for your project) to expose their
contents, and then select any file to view it in the editor. To expose all the
folders at once, Option-click the arrow next to the main project listing (that
is, “Hello World” in this case) when no subfiles are showing. If files are
showing, Option-click twice. The first click hides all the subfiles; the second
click reveals them.
Xcode
4’s editor supports code, property lists, images (display only), and Interface
Builder (IB) files. If you click, for example, on MainWindow_iPad.xib, you will
open an IB editor pane. That’s a big change from Xcode 3, where Interface Builder
was a separate program.
As
Figure 3-3 shows, Xcode’s GUI has undergone
massive changes from its 3.x incarnations. Whether you are new to iOS
development or transitioning from an earlier SDK, it’s well worth exploring the
Xcode workspace and its components. From a more integrated single-window
workspace to the migration of Interface Builder into the main Xcode
application, a lot of new features are waiting for you in Xcode 4.
Introducing
the Xcode Workspace
Although
it is not clear from Figure 3-3, the
standard Xcode Project window is composed of three primary sections. You can
best see this by clicking the Utility button at the top-right of the window.
This is the second button from the right, and looks like a white rectangle with
a smaller darker rectangle to its right. It is part of a set of seven buttons
grouped as three buttons (labeled “Editor”), then three buttons (labeled
“View”), then one button (labeled “Organizer”). Go ahead and click it to reveal
the Utility section to the right of the editor. You may want to resize the
workspace after exposing the Utility section.
Figure 3-4 shows the expanded workspace. It
consists of three areas and a toolbar. From left to right, those areas include
the Navigator pane, which allows you to browse project components, the Editor
pane in the center, which provides editors and viewers for your files, and the
Utility area to the right, which offers inspectors and library access.
Figure 3-4
The Xcode workspace consists of several areas, as shown here.
An
optional debugging pane appears at the bottom of the editor when a program
runs. You can show and hide it by clicking the debugger disclosure button at
the bottom-left of the editor or by clicking the center of the three view
buttons at the top-right corner of the Xcode window. The disclosure button is a
small rectangle with an upward (“show”) or downward (“hide”) triangle. The view
button is a rectangle with a darker embedded rectangle at its bottom.
A
small central activity view appears in the center of the toolbar at the top of
the window. It has a light blue color and can be found just under the window’s
title. This view shows you the current state of your project and any ongoing activities,
such as building code or an ongoing search. It looks a lot like the activity
view you see in iTunes. Application run, stop, and breakpoint controls can be
found just to the left of the activity view.
Controlling
the Workspace
The
seven buttons at the right of the workspace toolbar allow you to select the
ways you want to view your workspace. Starting from the left, these buttons are
as follows.
Editor
buttons—These
three editor buttons control how code is displayed in the central editor
window. Your choices are standard, assistant, and version:
- The
standard editor (Command-Return) displays a single source code pane.
- The
assistant (Command-Option-Return) allows you to split your viewer in two,
providing context-enhancing files in the secondary pane. The assistant can
automatically find files and display file counterparts (for example, showing
MyClass.h when viewing MyClass.m), superclass or subclass files, and so forth.
The assistant is an absolutely brilliant feature of Xcode 4. Customize your assistant
layout using the View > Assistant Layout submenu.
- The
version editor (Command-Shift-Option-Return) allows you to compare two versions
of a single file against each other, so you can spot differences and see what
has changed over time between separate commits.
- View
buttons—These
three buttons allow you to hide and show the Navigator (left), Debug (center),
and Utility (right) panes that appear in Figure
3-4. When all three are hidden, only the central editor pane appears. Doing
so provides what appears to be a simple editor window but with quick access
back to your project controls. You can also double-click files in the Navigator
to open them up in new windows, with the other panes hidden.
- Organizer
button—Looking
like a small window with smaller embedded rectangles, the Organizer button
provides one-click access to the Xcode Organizer window. The Organizer, which
is discussed later in this chapter, provides a single source for your mobile
device controls, documentation, project organization, and more. You can also
access the organizer by choosing Window > Organizer, or by pressing
Command-Shift-2 on the keyboard.
Note
-
Double-click any file listed in the Navigator to open it in a separate editor
window. By default, this hides the top toolbar. Restore it by selecting View
> Show Toolbar. There is no shortcut for this menu item by default, although
you can add one using a third-party utility such as Quickeys or via the
preferences’ key bindings pane.
Xcode
Navigators
The
left pane of the Xcode window doesn’t just list projects and folders. It
handles a lot more as well. It’s called the “navigator area” and it lets you
navigate information about projects in your workspace. Xcode 4 offers seven
specialized navigators. Each navigator organizes information so you can browse
through it. These navigators are accessed through the tab buttons at the top of
the Navigator pane. Xcode 4 navigators include the following items:
- The
Project Navigator (Command-1) lists the groups and files that comprise your
project. Selecting a file opens that file in an editor in the central pane. The
kind of editor presented depends on the selected file. A code file (.h, .m, and
so on) opens a code editor. Property list files, such as your Info.plist, open
a property list editor. Interface files (.storyboard and .xib files) open in an
Interface Builder (IB) editor, directly in the Xcode project window. This
differs from earlier versions of Xcode, where IB was a standalone program,
outside of Xcode.
- The
Symbol Navigator (Command-2) enumerates the classes, functions, and other
symbols used within your project. Selecting a symbol opens the declaring header
file, so you can instantly look up how the element is defined. The Utility >
Symbols (Quick Help) inspector pane, found in the right-hand area on the other
side of the editor, works synchronously with the Symbol Navigator by providing
instant contextual documentation for any selected symbol, whether you select
one from the Symbol Navigator or from the source editor.
Note
-
When the Utility > Symbols (Quick Help) inspector is hidden, you can
Option-click any symbol in the navigator or any text within a code editor to
pop up an Xcode 4 Quick Help window with the same contextual documentation
found in the Utility > Symbols pane. Use Option-double-click to open the
item in the Organizer’s documentation window. Two buttons appear at the
top-right of the Quick Help pop-up. The small book button leads to any existing
documentation. The file icon with the “h” on it links to the declaring header
file.
- The
Search Navigator (Command-3) provides an easy way to find text within your
project. You can search both in your workspace (including any projects that
have been added to the workspace) and in associated frameworks for instances of
that text. Choose the search method you want to use from the text field
pop-down as you type into the text field. A simple pop-up to the left of the
search field lets you use find-and-replace features as well. You are not limited
to searching via this Search Navigator. You can also search via Command-F (Edit
> Find > ...) in any text-based editor.
Note
-
The small magnifying glass icon at the left of the search field in the Search
Navigator plays an important role in controlling what documentation you search
through. Click the magnifying glass and select Find Options to reveal options
for matching your search phrase against source code.
- The
Issue Navigator (Command-4) provides a list of warnings and errors found during
your build requests. Use this pane to select each issue and highlight its
problem in the central code editor.
- The
Debug Navigator (Command-5) offers a way to examine threads and stacks during
execution. When you select an item, the editor will instantly jump to either
the source code or disassembly window, where you can see the current point of
execution.
- The
Breakpoint Navigator (Command-6) provides a global list of debugging
breakpoints within your project. Click any breakpoint to view it in-file in the
editor.
- The
Log Navigator (Command-7) allows you to view your build results as a history.
Click any past build to see the build log in the central editor pane.
Xcode
Utility Panes
Context-specific
helper panes appear in the right-hand utility pane. Like the left-hand
navigator, the utility area can be shown or hidden as needed. This area
consists of two sections: at the top is the Inspectors pane; at the bottom is
the Libraries pane. Inspectors provide information about and options to
customize a current selection. For example, when you select a label (a UILabel
instance) in the embedded Interface Builder, you can set
its alignment, background color, or dimensions using inspectors. Libraries
offer pre-built components that you can incorporate into your project, and can
include media and code snippets.
Both
panes provide a set of tabbed subpanes in a similar fashion to the Navigator
panes. Buttons appear at the top of each pane. Inspector buttons update to
match the context of the current selection. For example, the object attributes
and connections inspectors that appear for a UILabel
object do not
appear when working with text in a source code editor. That’s because those
Interface Builder–style inspectors have no meaning when working with source
code. The Utility pane updates to match the currently selected item in the
central editor.
Inspector
short cuts are Command-Option combined with a number, starting with 1 and 2 for
the File (Command-Option-1) and Quick Help (Command-Option-2) inspectors,
respectively. They increase numerically from there, depending on the available
inspector utility panes. Typically IB-style inspectors include Identity
(Command-Option-3), Attributes (Command-Option-4), Size (Command-Option-5), and
Connections (Command-Option-6). Xcode 3.x users should note that the
pane orders have been switched around a bit from what was used in 3.x
Interface Builder, plus the old keyboard shortcuts no longer apply.
Libraries
use Command-Control-Option shortcuts combined with a number. The library pane
provides access to file templates (Command-Control-Option-1), code snippets
(Command-Control-Option-2), objects (Command-Control-Option-3), and media
(Command-Control-Option-4). You can add your own custom elements into the code
snippets libraries to provide easy access to repeated code patterns.
Hide
or reveal the Utilities section by typing Command-Control-Option-0.
The
Editor Window
The
editor window includes a primary space, where content is displayed. Above this
space, you’ll find a “jump bar.” This bar simplifies finding other files using
any level of grouping. Each of the path-like elements provides a pop-up menu,
offering quick access to those elements. Jump bars appear in many Xcode 4
roles. They all work similarly and introduce a hierarchical way to move around
a structured system.
A
special menu item, the small button with eight rectangles at the very left of
the jump bar helps you find files related to the currently displayed item.
Options include code counterparts (.m/.h file pairs), superclasses, subclasses,
siblings, categories, included files, and more. This is a particularly powerful
menu that you shouldn’t overlook.
The
central space of the editor window offers Quick Look technology to provide
previews of nearly any kind of content you will add to your Xcode projects or
will need to use in support of that project. This means you can use the content
viewer not only for direct coding material, but also to review PDFs and keynote
presentations that relate to developing the project, for example.
Working
with Multiple Editor Windows
You
may want to work with several editor windows at once. To accomplish this, you
can create a new workspace window, work in one window using tabs, or detach a
floating editor. Both windows and tabs allow you to switch quickly between
various editors and files.
To
open new editor windows without taking an entire workspace with you,
double-click any filename. A floating editor window appears above your
workspace with the contents of that file.
To
create a new workspace window, choose File > New > New Window
(Command-Shift-T). The new window contains the same project or projects as the
original workspace. Changes to a file in one window or tab are mirrored to the
same file in other windows or tabs.
Note
-
To add line numbers to your source code editing windows, open Preferences
(Xcode > Preferences, Command-,). Select the Text Editing pane and check
Line Numbers.
To
use tabs, choose View > Show Tab Bar. This reveals a workspace tab bar
between the main toolbar and the panes below it. Create new tabs using File
> New Tab (Command-T) or right-click (Control-click) in the tab bar and
choose New Tab from the contextual pop-up. Alternatively, press Shift-Option
while clicking a filename in the navigator and click the + button at the top-right
to open the file in a new tab.
Xcode
tabs follow Apple’s standards, so if you’re used to using Safari tabs, they’ll
work similarly in Xcode. To navigate between tabs from the keyboard use
Command-Shift-[ to move left and Command-Shift-] to move right. Click + to add
a new tab to your window. You can pull tabs out into their own windows and can
drop tabs into existing windows by adding them to tab bars.
The
Cocoa Samurai blog (cocoasamurai.blogspot.com) created a number of Xcode 4
keyboard shortcut reference guides. These infographics, which are hosted at
github (github.com/Machx/Xcode-Keyboard-Shortcuts), provide an exhaustive guide
to the key combinations you can use to navigate through Xcode.
Note
-
Xcode provides full Undo support for a single session. You can even undo past a
previous save so long as you do so within the same session. That is, you cannot
close a project, reopen it, and then revert changes made before the project was
closed.
Review
the Project
When
Xcode creates your new project, it populates it with all the basic elements and
frameworks you need to build your first iOS application. Items you see in this
project include the following:
- Frameworks
> Foundation and Core Graphics frameworks—These essential
frameworks enable you to build your iPhone applications and are similar to the
ones found on OS X.
- Frameworks
> UIKit framework—This framework provides iOS-specific user
interface APIs and is key to developing applications that can be seen and
interacted with on the iPhone screen.
- Products
> HelloWorld.app—This placeholder is used to store your
finished application. Like on the Macintosh, iPhone applications are bundles
and consist of many items stored in a central folder.
- Supporting
Files > HelloWorld-Info.plist—This file describes your application
to the iPhone’s system and enables you to specify its executable, its
application identifier, and other key features. It works in the same way
Info.plist files work on the Mac. Localizable strings for the property list can
be found in the Supporting Files > InfoPlist.strings file(s).
- MainStoryboard_iPhone.storyboard
and MainStoryboard_iPad.storyboard—These Interface
Builder files create a minimally populated GUI for each platform. You will
modify the upcoming walkthrough.
- [Prefix]AppDelegate.h,
[Prefix]AppDelegate.m,
[Prefix]ViewController.h,
[Prefix]ViewController.m,
main.m—These
files contain a rough Objective-C skeleton that you can customize and expand to
create your application. The prefix used by these files is set in the new
project options screen. Feel free to browse through the code, but you will not
edit these files in the upcoming walkthrough. Instead, you use the way that
Xcode set them up and limit your modifications to the Interface Builder
storyboards.
Note
-
To add frameworks to your project in Xcode 4, select your blue project file in
the Project Navigator. In the central editor pane, click TARGETS > Target
Name in the very left column. Click Build Phases and open the Link Binary With
Libraries disclosure triangle. Click the + button, navigate to the framework
you wish to add (you’ll find standard frameworks under Device folders), select
it, and click Add. An options pane opens. Uncheck Copy items into destination
group’s folder (if needed), make sure that your target remains checked, and
click Finish. To remove a framework, simply select it and click -.
Open
the iPhone Storyboard
Locate
the MainStoryboard_iPhone.storyboard file in the Project Navigator. Storyboards
store Interface Builder layouts and can include all the screens (called
“scenes”) for a single application. Select the storyboard file to open it in
the central editor so you can begin to edit the file. You will see a grid
pattern in the background of the editor and a scene list on the left side of
the window. This list initially consists of the single Hello World View
Controller Scene. The scene appears in the gridded area and consists of an
empty view on top and an associated object dock beneath it. Figure 3-5 shows how this looks.
Figure 3-5
The Interface Builder window for an iPhone storyboard. A small dock floats
below each storyboard scene, offering access to objects associated with its
view.
The
two icons in the dock represent elements of the interface you’re editing. On
the right is the view’s owner—in this case, its view controller. It represents
the view controllers attached to the view.
View
controllers don’t have a visual presentation. They manage views, but they don’t
display anything of their own. Each view controller has a property called “view”
that is set to some UIView
responsible for
providing the actual onscreen presentation. Here, that view is displayed above
the dock. You can see more about the controller by selecting it and opening
View > Utilities > Show Identity Inspector. Observe the class listed in
the inspector (ESViewController
or similar).
The
view controller element in the dock is called a “proxy.” A proxy plays a role
in IB but the object that it represents (the view controller) is not itself
embedded in the .storyboard archive. This proxy represents the object that
loads and owns the view.
To
see how items are connected to each other, choose View > Utilities > Show
Connections Inspector. You see an outlet listed called “view.” Hover your mouse
over this outlet and the view darkens. A small tooltip (saying “View”) appears
as well. That’s because the view
outlet for
your view controller is already connected to that view. Outlet is IB-talk for
“instance variable.”
The
other icon, the one that appears in the left position of the dock, is called
First Responder. It looks like a dark orange cube with the number 1 on it. Like
the view controller, it’s a proxy object. It represents the onscreen object
that is currently responding to user touches. During the lifetime of an
application, the first responder changes as users interact with the screen. For
example, imagine a form. As the user touches each text field in that form, that
field becomes active and assumes the first responder role. At times you want to
allow interface elements (such as buttons and switches) to control whatever
item is the first responder. Connecting to this proxy in Interface Builder
allows you to do so.
Edit
the View
To
start customizing, click the big white view. By default, this view is empty
although it shows a status bar at the top. It’s up to you to customize this and
add any content. To do so, you rely on two tools from the Utility area: the
Interface Builder object library and the inspector.
Choose
View > Utilities > Show Attributes Inspector (Command-Option-4). The
Attributes Inspector lets you adjust the properties of the currently selected
object—in this case, the view that you are editing. In the inspector, locate
the View > Background Listing with its colored swatch. Click the swatch and
choose a new color from the Colors palette. The view you are editing
automatically updates its background color.
Next,
open the object library by choosing the third icon at the top of the bottom
pane. Alternatively, select View > Utilities > Show Object Library
(Command-Control-Option-3). This library (see Figure
3-6) presents a list of prebuilt Cocoa Touch elements you can use in your
IB files. These include both abstract elements such as view controllers as well
as visual components such as buttons and sliders. Enter label
in the search field at the bottom of the library. Drag the label from the
middle pane and drop it onto your window. (Alternatively, double-click the
label in the library. This automatically adds that item to your window.)
Figure 3-6
The Interface Builder object library.
Once
it is dragged to the view, double-click the label and change the words from
“Label” to “Hello World.” You can also move the label around in the window to
appeal to your aesthetic sensibilities or set its location in the Size Inspector.
The Attributes Inspector allows you to set the font face and size, as well as
the text color. You may need to resize your label to accommodate the new size.
Unselect “Autoshrink” and note that there are two places to set the font size.
The field in the main inspector sets the minimum font size for the
label. The pop-up for the font sets the desired font size.
Save
your project with File > Save (Command-S). You have now customized your
iPhone window with this content.
Next,
customize the iPad interface. Return to the Project Navigator and select
MainStoryboard_iPad.storyboard. You’ll notice that the iPad presentation is far
larger than the iPhone one. You may not be able to see the entire iPad
interface at once, even on relatively large screens.
Interface
Builder allows you to double-click in the grid background to shrink the
presentation to a more manageable size, but you cannot perform edits in this
mode. You can also use the new zoom/shrink buttons at the bottom-right of the
editor window. Many developers find it worth investing in a large vertical
monitor rather than a horizontal one in order to better work with iPad edits in
IB.
As
before, change the view’s background color, add a label (“Hello World on iPad,”
perhaps) and mess with its font and placement. Again, save your project (File
> Save, Command-S).
Run
Your Application
Locate
the pop-up in the workspace toolbar just to the right of the Start/Stop buttons
at the top-left of the window. From this pop-up choose Hello World > iPhone
Simulator. This tells Xcode to compile your project for the Macintosh-based
iPhone simulator. If more than one simulator choice presents, select the most
recent SDK (that is, 5.3 rather than 5.0).
Click
the run button (by default it looks like a “Play” button) or type Command-R and
then wait as Xcode gets to work. It takes a few seconds to finish compiling,
and then Xcode automatically launches the simulator, installs your project, and
runs it. Figure 3-7 shows the result, the Hello
World application running on the simulator.
Figure 3-7
The customized Hello World application runs on the simulator.
After
testing the application on the iPhone simulator, click the stop button (to the
right of the run button) and test the application using the iPad simulator. Select
Hello World > iPad Simulator from the pop-up and again click the run button.
Using
the Simulator
The
iOS SDK simulator makes it possible to test applications on the Macintosh using
many of the same actions a user would perform on an actual device. Because the
Macintosh is not a handheld touch-based mobile system, you must use menus,
keyboard shortcuts, and the mouse or trackpad to approximate iPhone-style
interactions. Table 3-1 shows how to perform these tasks via the simulator.
Table
3-1 Simulator Equivalents for iPhone Actions
Action
| Simulator Equivalent
|
Selecting
the device
| Use
Hardware > Device to simulate an original iPhone, Retina iPhone, or
iPad-style device. Firmware versions are selectable via Hardware >
Version.
|
Rotating
the device
| Hardware
> Rotate Left (Command-left arrow) and Hardware > Rotate Right
(Command-right arrow). The simulator supports all four major interface
orientations: portrait, landscape left, landscape right, and portrait upside
down. You cannot simulate face-up or face-down orientations.
|
Shaking
the device
| Hardware
> Shake Gesture (Command-Control-Z). This simulates a shake using a motion
event but does not simulate other accelerometer actions. I encourage you to
avoid building applications that depend on users shaking devices, no matter
how cool the feature appears.
|
Pressing
the Home key
| Click the
Home button on the simulator screen or choose Hardware > Home
(Command-Shift-H).
|
Locking
the device
| Hardware
> Lock (Command-L).
|
Tapping
and double-tapping
| Click
with the mouse, either a single- or double-click.
|
Tapping
on the keyboard
| Click the
virtual keyboard or type on the Mac keyboard. You can use many Mac-style
shortcuts for ease of testing, including Command-A, Command-C, and so on.
|
Dragging,
swiping, and flicking
| Click,
drag, and release with the mouse. The speed of the drag determines the
action. For flicks, drag very quickly.
|
Pinching
in or out
| Press and
hold the Option key on your keyboard. When the two dots appear, drag them
toward each other or away from each other. Hold down the Shift key to move
the dot’s origin point.
|
Running
out of memory
| Hardware
> Simulate Memory Warning. This allows you to simulate a condition of low
available memory, letting you test how your application responds.
|
In-progress
phone call (visual display only)
| Hardware
> Toggle In-Call Status Bar. On the iPhone, you can run an application
while on a phone call. The in-call bar appears at the top of the screen for
the duration of the call.
|
Attaching
a keyboard
| Simulate
the detection of a Bluetooth or docked hardware keyboard by selecting
Hardware > Simulate Hardware Keyboard.
|
Attaching
TV Out cables
| Choose
Hardware > TV Out to simulate the attachment of a VGA or HDMI cable to the
dock connector. Use this to test your external screen code, and specifically
to catch screen-attached and -detached notifications. A floating window shows
the simulated output.
|
Changing
zoom
| Change
the magnification of the simulator by selecting Window > Scale. Choose
from 100%, 75%, and 50%.
|
Simulating
a printer
| Choose
File > Open Printer Simulator to test your software with AirPrint. You can
also use this simulator to test printing from a device. The printed output
opens in Preview.
|
Capturing
screenshots
| Choose
File > Save Screen Shot (Command-S) or copy the screen with Edit > Copy
Screen (Command-Control-C).
|
Setting a
simulated location
| Use the
Debug > Location menu to simulate where the iPhone is being used. Choose
from a (stationary) custom location, Apple’s HQ, Apple Stores, a city bike
ride/run, or a drive down the freeway.
|
Slowing
down animations
| Choose
Debug > Toggle Slow Animations to allow you to better view animations over
a longer period of time. Use this feature to spot inconsistencies and flaws
in your animations.
|
Highlighting
potential rendering trouble spots
| Use the
four Debug > Color options to locate potential presentation issues. The
items, which are toggled on and off via menu selection, include blended
layers, copied images, misaligned images, and elements rendered off-screen.
|
Resetting
the simulator
| Choose
iOS Simulator > Reset Contents and Settings to restore your simulator to
its “factory fresh” original condition, deleting all current applications,
settings, and user data.
|
Simulator:
Behind the Scenes
Because
the simulator runs on a Macintosh, Xcode compiles simulated applications for
the Intel chip. Your application basically runs natively on the Macintosh
within the simulator using a set of Intel-based frameworks that mirror the
frameworks installed with iOS onto actual units. The simulator versions of
these frameworks are typically located in the Xcode developer directory, in
/Developer/Platforms/iPhoneSimulator.platform/Developer/
SDKs/iPhoneSimulator5.0.sdk/System/Library or some similar location. The actual
location will vary by the version of the SDK you are using and where you have
installed the SDK. The /Developer folder is the default location, but you can
easily override this.
You
can find your applications in your home’s Library/Application Support folder.
They are stored in iPhone Simulator/ in one of many firmware-specific folders,
such as 3.1.2/, 4.2/, and 6.1/ under User/Applications/. It’s helpful to visit
these folders to peek under the hood and see how applications get deployed to
the iPhone; these User/ Applications/ folders mimic device installations. Other
interesting development folders include the following:
- /Developer/Platforms/iPhoneSimulator.platform/Developer/
Applications—Default location of the actual iPhone simulator
application.
- /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/
iPhoneSimulatorX.X.sdk/Applications—Location of the
simulator’s built-in applications, including Mobile Safari, the Address Book,
and so forth. Replace X.X with the firmware version.
- /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/
iPhoneSimulator5.0.sdk/System/Library/Frameworks—Location of the Cocoa
Touch frameworks you can link to from your application.
- /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/
Templates/Project Templates/Application—Location of the
individual project templates shown in Figure 3-1.
- ~/Library/MobileDevice/Provisioning
Profiles—Folder
that stores your iPhone Portal provisioning profiles.
- ~/Library/Developer/Xcode/Archives—Folder that
stores archives built with the Build > Build and Archive option in Xcode.
Archived applications appear in your Xcode Organizer, where they can be
validated, shared, and submitted to iTunes Connect.
- ~/Library/Developer/Xcode/DerivedData—Build and log
folder.
- ~/Library/Developer/Xcode/Snapshots—Project
version control snapshots.
- ~/Library/Developer/Shared/Xcode/Screenshots/—Folder for
screenshots taken with the Organizer.
- ~/Library/Developer/Shared/Project
Templates/—Add custom templates to this folder to have them appear
in the New Project screen.
- ~/Library/MobileDevice/Software
Images—Folder
that stores iOS firmware files (.ipsw files) that can be installed onto your
devices.
- ~/Library/Application
Support/MobileSync/Backup—Folder where iTunes stores iPhone, iPod
touch, and iPad backup files.
Note
-
Application archives let you share applications as .ipa files. They also allow
you to run the same validation tests that iTunes Connect uses to confirm that
an application is properly signed with a development certificate before or as
you submit your apps.
Each
application is stored in an individual sandbox. The name of the sandbox is
random, using a unique code (generated by CFUUIDCreateString()
). You can zip
up a sandbox folder and be able to share it between Macintoshes. The other
Macintosh will need Xcode to be installed in able to access the simulator and
its frameworks.
Each
sandbox name hides the application it’s hosting, so you must peek inside to see
what’s there. Inside you find the application bundle (HelloWorld.app, for
example), a Documents folder, a Library folder, and a temporary (/tmp) folder.
While running, each application is limited to accessing these local folders.
They cannot use the main user library as applications might on a Macintosh.
With
the exception of the Library/Caches folder, all the materials in an
application’s Documents and Library folders are backed up by iTunes when
deployed to a device. The tmp folder is not backed up by iTunes. Use the Caches
folder to store large, changing application-support data files that need to
persist. Use the tmp folder for materials that iOS can dispose of between
application launches.
If
you want to clean out your applications’ sandbox folders, you can delete files
directly while the simulator is not running. You can also delete all the
simulator data by choosing iPhone Simulator > Reset Contents and Settings
from the simulator itself. This erases applications, their sandboxes, and any
current settings, such as nondefault language choices, that affect how your
simulator runs.
Alternatively,
use the press-and-hold-until-it-jiggles interface on the simulator that you’re
used to on the iPhone device itself. After you press and hold any icon for a
few seconds, the application icons start to jiggle. Once in this edit mode, you
can move icons around or press the corner X icon to delete applications along
with their data. Press the Home button to exit edit mode.
Although
applications cannot access the user library folder, you can. If you want to
edit the simulator’s library, the files are stored in the iPhone
Simulator/User/Library folder in your home Application Support folder. Editing
your library lets you test applications that depend on the address book, for
example. You can load different address book sqlitedb files into
Library/AddressBook to test your source with just a few or many contacts.
Note
-
The iPhone simulator and Mac OS X use separate clipboards. The simulator stores
its own clipboard data, which it gathers from iOS copy/paste calls. When you
use Edit > Paste (Command-V), the simulator pastes text from the Macintosh
clipboard into the simulator’s clipboard. You can then use the simulator’s Edit
menu (double-tap in a text box) to paste from the iOS clipboard into simulator
applications.
Sharing
Simulator Applications
Simulator-compiled
applications provide an important way to share test builds when developers are
denied access to new hardware or when beta firmware is not widely distributed.
They can also support interface design testing in advance of actual device
deployment. Although unsuitable for full debugging and end-user usability tests
(see Chapter 1, “Introducing the iOS SDK”), simulator builds do have a role and
a purpose in iOS application life cycle.
To
share an app, zip up its entire sandbox folder from one Macintosh and then
extract it to another Mac’s simulator application folder.
The
Minimalist Hello World
While
exploring the iOS SDK, and in the spirit of Hello World, it helps to know how
to build parsimonious applications. That is, you should know how to build an
application completely from scratch, without five source files and two
interface files. Here is a walkthrough showing you exactly that—a very basic
Hello World that mirrors the approach shown with the previous Hello World
example but that manages to do so with one file and no .storyboard or xib
files.
Start
by creating a new project (File > New Project, Command-Shift-N) in Xcode.
Choose Empty Application, click Next, enter Hello World as the
product name, and set your company identifier as needed (mine is com.sadun).
Set the device family to Universal, uncheck Use Core Data, uncheck Include Unit
Tests, and click Next. Save it to your desktop.
When
the project window opens, select the two App Delegate files (.h and .m) from
the project navigator and click delete or backspace to delete them. Choose
Delete (formerly Also Move to Trash) when prompted.
Open
Hello World > Supporting Files > main.m and replace its contents with
Listing 3-1. The source is included in the sample code for this book (see the
Preface for details), so you don’t have to type it in by hand.
Listing
3-1 Reductionist main.m
#import <UIKit/UIKit.h>
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
@interface TestBedAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
}
@end
@implementation TestBedAppDelegate - (UIViewController *) helloController
{
UIViewController *vc = [[UIViewController alloc] init];
vc.view.backgroundColor = [UIColor greenColor];
UILabel *label = [[UILabel alloc] initWithFrame:
CGRectMake(0.0f, 0.0f, window.bounds.size.width, 80.0f)];
label.text = @"Hello World";
label.center = CGPointMake(CGRectGetMidX(window.bounds),
CGRectGetMidY(window.bounds));
label.textAlignment = UITextAlignmentCenter;
label.font = [UIFont boldSystemFontOfSize: IS_IPHONE ? 32.0f : 64.0f];
label.backgroundColor = [UIColor clearColor];
[vc.view addSubview:label];
return vc;
}
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
window = [[UIWindow alloc] initWithFrame:
[[UIScreen mainScreen] bounds]];
window.rootViewController = [self helloController];
[window makeKeyAndVisible];
return YES;
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
int retVal =
UIApplicationMain(argc, argv, nil, @"TestBedAppDelegate");
return retVal;
}
}
So
what does this application do? It builds a window, colors the background, and
adds a label that says “Hello World.” In other words, it does exactly what the
first Hello World example did, but it does so by hand, without using Interface
Builder.
The
application starts in main.m by establishing the autorelease pool and calling UIApplicationMain()
. From there, control passes to the
application delegate, which is specified as the last argument of the call by
naming the class. This is a critical point for building a non–Interface Builder
project, and one that has snagged many a new iPhone developer.
The
delegate, receiving the application:didFinishLaunchingWithOptions:
message,
builds a new window, querying the device for the dimensions (bounds) of its
screen. It creates a new view controller, assigns that controller as its rootViewController
property, and orders it out, telling it to
become visible. Using the device’s screen bounds ensures that the main window’s
dimensions matches the device. For older iPhones, the window will occupy a
320·480-pixel area, for the iPhone 4 and later, 640·960 pixels, for the first
two generations of iPads, 768·1024 pixels.
The
helloController
method initializes
its view controller’s view by coloring its background and adding a label. It
uses UI_USER_INTERFACE_IDIOM()
to detect
whether the device is an iPhone or iPad, and adjusts the label’s font size
accordingly to either 32 or 64 points. In real-world use, you may want to
perform other platform-specific adjustments such as choosing art or setting
layout choices.
As
you can see, laying out the label takes several steps. It’s created and the
text added, centered, aligned, and other features modified. Each of these
specialization options defines the label’s visual appearance, steps that are
much more easily and intuitively applied in Interface Builder. Listing 3-1
demonstrates that you can build your interface entirely by code, but it shows
how that code can quickly become heavy and dense.
In
Xcode, the Interface Builder attributes inspector fills the same function. The
inspector shows the label properties, offering interactive controls to choose
settings such as left, center, and right alignment. Here, that alignment is set
programmatically to the constant UITextAlignmentCenter
, the
background color is set to clear, and the label programmatically moved into
place via its center
property. In the end,
both the by-hand and Interface Builder approaches do the same thing, but here
the programmer leverages specific knowledge of the SDK APIs to produce a series
of equivalent commands.
Browsing
the SDK APIs
iOS
SDK APIs are fully documented and accessible from within Xcode. Choose Help
> Developer Documentation (Command-Option-Shift-?) to open the Xcode
Organizer > Documentation browser. The Documentation tab will be selected at
the top bar of the window. Other tabs include iPhone, Repositories, Projects,
and Archives, each of which plays a role in organizing Xcode resources.
The
documentation you may explore in this window is controlled in Xcode’s
preferences. Open those preferences by choosing Xcode > Preferences
(Command-,) > Documentation. Use the GET buttons to download document sets.
Keep your documentation up to date by enabling “Check for and install updates
automatically.”
In
the Developer Documentation organizer, start by locating the three buttons at
the top of the left-hand area. From left to right these include an eye, a
magnifying glass, and an open book. The eye links to explore mode, letting you
view all available documentation sets. The magnifying glass offers interactive
search, so you can type in a phrase and find matching items in the current
document set. The open book links to bookmarks, where you can store links to
your most-used documents.
Select
the middle (magnifying glass) search button. In the text field just underneath
that button locate another small magnifying glass. This second magnifying glass
has a disclosure triangle directly next to it. Click that disclosure and select
Show Find Options from the pop-up menu. Doing so reveals three options below
the text field: Match Type, Doc Sets, and Languages. Use the Doc Sets pop-up to
hide all but the most recent iOS documentation set. This simplifies your search
results so you do not find multiple hits from SDK versions you’re not actually
using.
Enter
UILabel into the search field to find a list of API results
that match UILabel
, as well as full text
and title matches. The first item in the results list should link to the iOS
Library version of the documentation. Refer to the jump bar at the top of the
main area to locate which library you are viewing. This should read something
like iOS Library > User Experience > Windows & Views > UILabel
Class Reference. The UILabel Class Reference (see Figure
3-8) displays all the class methods, properties, and instance methods for
labels as well as a general class overview.
Figure 3-8
Apple offers complete developer documentation from within Xcode itself.
Apple’s
Xcode-based documentation is thorough and clear. With it you have instant
access to an entire SDK reference. You can look up anything you need without
having to leave Xcode. When material goes out of date, a document subscription
system lets you download updates directly within Xcode.
Xcode
4 lost the handy class overview that appeared to the left of documentation in
Xcode 3. The jump bar at the top embeds the same organization features (namely
overview, tasks, properties, and so on). If you’d rather view the material with
the old-style Developer Library overview, right-click in the class reference
area and choose Open Page in Browser. Figure 3-9
shows the browser-based presentation with that helpful at-a-glance class Table
of Contents to the left of the core material.
Figure 3-9
The “Table of Contents” view is no longer available from within Xcode itself
but can be accessed via Open Page in Browser.
Converting
Interface Builder Files to Their Objective-C Equivalents
A
handy open-source utility by Adrian Kosmaczewski allows you to convert
Interface Builder files to Objective-C code. With it, you can extract all the
layout information and properties of your visual design and see how that would
be coded by hand. nib2objc does exactly what its name suggests. With it, you
can generate converted code that takes into account the class constructors,
method calls, and more. It works on .xib and .storyboard files, although some
newer features such as segues are not yet exposed; under the hood both formats
are simply XML.
Listing
3-2 shows the result of running nib2objc on the .xib file used in the first
walkthrough. Compare it to the far simpler (and less thorough) by-hand version
in Listing 3-1. It performs more or less the same tasks. It creates a new label
and then adds the label to the window. However, this conversion utility exposes
all the underlying properties, of which just a few were edited in Listing 3-1.
To
peek at the original IB XML, open the storyboard file in Text Edit. Issue open -e
from the Terminal command line while in the HelloWorld
project folder in the en.lproj subfolder:
open -e MainStoryboard_iPad.storyboard
Note
-
nib2obj is hosted at http://github.com/akosma/nib2objc
and issued under a general “Use this for good not evil” style of license.
Listing
3-2 HelloWorldViewController.xib after Conversion to Objective-C
UIView *view3 = [[UIView alloc] initWithFrame:
CGRectMake(0.0, 20.0, 320.0, 460.0)];
view3.frame = CGRectMake(0.0, 20.0, 320.0, 460.0);
view3.alpha = 1.000;
view3.autoresizingMask =
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleBottomMargin;
view3.backgroundColor =
[UIColor colorWithRed:0.963 green:1.000 blue:0.536 alpha:1.000];
view3.clearsContextBeforeDrawing = YES;
view3.clipsToBounds = NO; view3.contentMode = UIViewContentModeScaleToFill; view3.hidden = NO; view3.multipleTouchEnabled = NO; view3.opaque = YES; view3.tag = 0;
view3.userInteractionEnabled = YES;
UILabel *view6 = [[UILabel alloc] initWithFrame:
CGRectMake(72.0, 150.0, 175.0, 160.0)];
view6.frame = CGRectMake(72.0, 150.0, 175.0, 160.0);
view6.adjustsFontSizeToFitWidth = YES;
view6.alpha = 1.000; view6.autoresizingMask =
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin;
view6.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
view6.clearsContextBeforeDrawing = YES;
view6.clipsToBounds = YES;
view6.contentMode = UIViewContentModeLeft; v
iew6.enabled = YES; view6.hidden = NO;
view6.lineBreakMode = UILineBreakModeTailTruncation;
view6.minimumFontSize = 10.000;
view6.multipleTouchEnabled = NO;
view6.numberOfLines = 1; view6.opaque = NO;
view6.shadowOffset = CGSizeMake(0.0, -1.0);
view6.tag = 0; view6.text = @"Hello World";
view6.textAlignment = UITextAlignmentLeft;
view6.textColor = [UIColor colorWithRed:0.000 green:0.000 blue:0.000 alpha:1.000];
view6.userInteractionEnabled = NO;
[view3 addSubview:view6];
[view2 addSubview:view3];
Using
the Debugger
Xcode’s
integrated debugger provides a valuable tool for iPhone application
development. This walkthrough shows you where the debugger is and provides a
simple grounding for using it with your program. In these steps, you discover
how to set breakpoints and use the debugger console to inspect program details.
These steps assume you are working on the second, minimalist Hello World
example just described and that the project window is open and the main.m file
displayed.
Set
a Breakpoint
Locate
the helloController
method in the main.m
file of your Hello World project. Click in the leftmost Xcode window column,
just to the left of the label
assignment
line. A blue breakpoint indicator appears (see Figure
3-10). The dark blue color means the breakpoint is active. Tap once to
deactivate—the breakpoint turns light blue—and once more to reactivate.
Figure 3-10
Blue breakpoint indicators appear in the gutter to the left of the editor area.
You can reveal the debugger at the bottom of the workspace by clicking the
Debugger disclosure button while running an application or by clicking the
center of the three View buttons at the top-right of the workspace window at
any time.
Remove
breakpoints by dragging them offscreen or right-clicking them; add them by
clicking in the column, next to any line of code. Once added, your breakpoints
appear in the workspace’s Breakpoint Navigator (Command-6). You can delete
breakpoints from the navigator (select, then press the Delete button) and can deactivate
and reactivate them from there as well.
Open
the Debugger
Compile
the application (Product > Build, Command-B) and run it (Product > Run,
Command-R). The simulator opens, displays a black screen, and then pauses.
Execution automatically breaks when it hits the breakpoint. A green bar appears
next to your breakpoint, with the text “Thread 1: Stopped at breakpoint 1.”
In
Xcode, the debugging pane appears automatically as you run the application. You
can reveal or hide it manually by clicking the middle of the three View buttons
at the top-right of the workspace window; it looks like a rectangle with a dark
bottom. When the debugger is shown, you can drag its jump bar (not the one at
the top of the editor window, but the one at the top of the debugger) upward to
provide more room for your output.
The
debugger provides both a graphical front end for inspecting program objects as
well as a text-based log area with an interactive debugger console. Xcode
offers two command-line debuggers: gdb and lldb. The LLDB project (hosted at http://llvm.org) expands upon the standard GNU
debugger (gdb) with improved memory efficiency and Clang compiler integration.
Select
which debugger you wish to use by editing your project scheme, as shown in Figure 3-11. Select Edit Scheme from the pop-up
at the left of your toolbar at the top of your workspace window just to the
right of the Run and Stop buttons. (Make sure you’re selecting the Hello World
part of the pop-up, not the iPhone or iPad simulator part.) Use the Info >
Debugger pop-up to switch between GDB and LLDB. Click OK.
Figure 3-11
The project scheme editor allows you to select which debugger you prefer to
use.
Inspect
the Label
Once
stopped at the breakpoint, the interactive debugger and the debugger command
line let you inspect objects in your program. Using lldb, you can look at the
label by typing print-object label
or, more
simply po label
at the command line.
Use print
or p
to print
non-objects, such as integer values.
(lldb) po label
(UILabel *) $3 = 0x06a3ded0 <UILabel: 0x6a3ded0; frame = (0 0; 320 80);
clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x6a3df40>>
At
this time, the label’s text has not yet been set and it has not yet been added
to the view controller’s view. You can confirm that the label is not yet added
to the view by looking at the view controller’s view’s subviews, currently an
empty array, and the label’s superview, currently nil
.
(lldb) po [[vc view] subviews]
(id) $4 = 0x06811e20 <__NSArrayI 0x6811e20>(
) (lldb) po [label superview]
(id) $5 = 0x00000000 <nil>
(lldb)
You
can also view the label directly using the inspector at the left side of the
debugger. Locate label
and click the
disclosure triangle to the left of it to show the properties of the label
object. The label’s _text
field is set to <nil>
.
The
Step Into button appears to the left of the debugger jump bar. It looks like an
arrow pointing down to a small black line. Click it once. The text assignment
executes and the green arrow moves down by one line. The summary of the label.text
updates. It should now say something like “Hello World
(iPhone).” Confirm by inspecting the label from the command line by typing po label
again. The label has updated its text instance variable
to Hello World.
(lldb) po label (UILabel *) $12 = 0x06a3ded0 <UILabel: 0x6a3ded0; frame = (0 0; 320 80); text = 'Hello World'; clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer: 0x6a3df40>>
If
you want to get really crazy, you can override values directly by using p
or print
to make interpreted calls during the
execution of your application. This call changes the label text from “Hello
World” to “Bye World.” It does that by executing the items within the square
brackets, casting the void return to an integer, and then printing the
(meaningless) results.
(lldb) p (int)[label setText:@"Bye World"]
(int) $13 = 117671936
(lldb) po label (UILabel *) $14 = 0x06a3ded0 <UILabel: 0x6a3ded0; frame = (0 0; 320 80);
text = 'Bye World';
clipsToBounds = YES; userInteractionEnabled = NO; layer = <CALayer:
0x6a3df40>>
Set
Another Breakpoint
You
can set additional breakpoints during a debugging session. For example, add a
second breakpoint just after the line that sets the text alignment to center,
on the line that sets the background color. Just click in the gutter next to label.backgroundColor
, or wherever you want to set the breakpoint.
Confirm
that the current alignment is set to 0, the default value, by inspecting the
label’s textLabelFlags
—you will have to open
the disclosure triangles in the column to the left of the lldb interface to see
these label attributes. With the new breakpoint set, click the Resume button.
It appears as a right-pointing triangle with a line to its left.
HelloWorld
resumes execution until the next breakpoint, where it stops. The green arrow
should now point to the backgroundColor
line, and the
explicit alignment flag updates from 0 to 1 as that code has now run, changing
the value for that variable.
(lldb) p (int) [label textAlignment]
(int) $19 = 1
You
can further inspect items by selecting them in the left-hand debugging
inspector, right-clicking, and choosing Print Description from the contextual
pop-up menu. This sends the description
method to the
object and echoes its output to the console.
Note
-
Remove breakpoints by dragging them out from the left column or by deleting
them in the Breakpoint Navigator.
List
your breakpoints by issuing the breakpoint list
command. Lldb
prints out a list of all active breakpoints.
(lldb) breakpoint list
Current breakpoints:
1: file ='main.m', line = 26, locations = 1, resolved = 1
baton: 0x11b2dd380
1.1: where = Hello World`-[TestBedAppDelegate helloController] + 365 at
main.m:26,
address = 0x0000211d, resolved, hit count = 1
3: file ='main.m', line = 30, locations = 1, resolved = 1
baton: 0x12918d6c0
3.1: where = Hello World`-[TestBedAppDelegate helloController] + 912 at main.m:30,
address = 0x00002340, resolved, hit count = 0
Note
-
Learn more about setting and controlling breakpoints by visiting the LLVM
website. The official lldb tutorial is found at
lldb.llvm.org/tutorial.html.
Backtraces
The
bottom pane of the debugging window offers text-based debugger output that can
mirror results from other panes. For example, open the Debug Navigator and view
the application by thread, disclosing the trace details for Thread 1. This
provides a trail of execution, showing which functions and methods were called,
in which order to get you to the current point where your application is.
Next,
type backtrace or bt at the text debugger
prompt to view the same trace that was shown in that navigator. After stopping
at the second breakpoint, the backtrace should show that you are near (for
example, line 26 in the source from main.m). You will see this line number
toward the beginning of the trace, with items further back in time appearing
toward the end of the trace. This is the opposite of the view shown in the
Debug Navigator, where more recent calls appear toward the top of the pane.
Console
This
bottom text-based debugger is also known as the console. This pane is where
your printf
, NSLog
, and CFShow
messages are sent by default when running in standard
debug mode or when you use the simulator. You can resize the console both by
adjusting the jump bar up or down and also by dragging the resize bar between
the left and right portions of the debugger. If you want, you can use the
show/hide buttons at the top-right of the debugger. Three buttons let you hide
the console, show both the console and the visual debugger, or show only the
console. To the left of these three buttons is a Clear button. Click this to
clear any existing console text.
To
test console logging, add a NSLog(@"Hello World!");
line to your
code; place it after adding the label as a window subview. Remove any existing
breakpoints and then compile and run the application in the simulator. The log
message appears in the Debug area’s console pane. The console keeps a running
log of messages throughout each execution of your application. You can manually
clear the log as needed while the application is running.
Add
Simple Debug Tracing
If
you’re not afraid of editing your project’s .pch file, you can add simple
tracing for your debug builds. Edit the file to add the following macro
definition:
#ifdef DEBUG
#define DebugLog(...) NSLog(@"%s (%d) %@", __PRETTY_FUNCTION__, __LINE__,
[NSString stringWithFormat:__VA_ARGS__])
#else
#define DebugLog(...)
#endif
Memory
Management
iOS
does not offer garbage collection. It relies on a reference counted memory
management system. The new LLVM ARC extensions introduce automated reference
counting, letting the compiler take care of many management issues for you. ARC
automates when objects are retained and released, simplifying development. That
doesn’t mean you don’t have to worry about memory:
- Even
with ARC, you remain responsible for letting go of resources that create
low-memory conditions. If you hold onto lots of multimedia assets such as
video, audio, and images, you can exhaust memory—even in ARC-compiled
applications.
- Many
developers continue to use manual retain/release (MRR) development, especially
to avoid refactoring production-critical code. Using MRR means you must control
when objects are created, retained, and released in that code because ARC will
not handle that for you.
- ARC
does not automatically extend to Core Foundation and other C-based class code.
Even if CF classes are toll-free bridged, ARC does not assume control of their
instances until they are bridged into the Objective-C world.
As
a developer, you must strategize how to react to low-memory conditions. Use too
much memory and the iPhone warns your application delegate and UIViewController
s. Delegates receive applicationDidReceiveMemoryWarning:
callbacks; view
controllers get didReceiveMemoryWarning
. Continue to
use too much memory and the iPhone will terminate your application, crashing
your user back to the iOS home screen. As Apple repeatedly points out, this is
probably not the experience you intend for your users, and it will keep your
application from being accepted into the App Store.
You
must carefully manage memory in your programs and release that memory during
low-memory conditions. Low memory is usually caused by one of two problems:
leaks that allocate memory blocks that can’t be accessed or reused, and holding
onto too much data at once. Even on newer iOS devices, such as the iPad 2, your
application must behave itself within any memory limits imposed by the
operating system.
Every
object in Objective-C is created with an integer-based retain count. So long as
that retain count remains at 1 or higher, objects will not be deallocated. That
rule applies in ARC code just as it applies in MRR. It is up to you as a
developer to implement strategies that ensure that objects get released at the
time you will no longer use them.
Every
object built with alloc
, new
,
or copy
starts with a retain value of 1.
Whether developing with ARC or MRR, if you lose access to an object without
reducing the count to 0, that lost object creates a leak (that is, memory that
is allocated and cannot be recovered). The following code leaks an array:
NSArray *leakyArray = [NSArray arrayWithObjects:@"Hello", @"World", nil];
CFArrayRef leakyRef = (__bridge_retained CFArrayRef) leakyArray;
leakyRef = nil;
Recipe:
Using Instruments to Detect Leaks
Instruments
plays an important role in tuning your applications. It offers a suite of tools
that lets you monitor and evaluate performance. For example, its leak detection
lets you track, identify, and resolve memory leaks within your program. Recipe
3-1 shows an application that creates two kinds of leaks on demands: one
created by using CF bridging without a proper release, the other by introducing
a strong reference cycle that cannot be resolved by ARC at the termination of
its method.
To
see Instruments in action, load the sample project for Recipe 3-1. Choose one
of the simulator options as your destination from the leftmost pop-up in the
toolbar at the top of your workspace, just to the right of the Run and Stop
buttons. Then click and hold the Run button until the pop-up shown in Figure 3-12 appears. Choose Profile and then
agree to whatever impediments Xcode throws in your direction (if any), such as
stopping any currently running application, and so on.
Figure 3-12
Select Profile from the Run button’s pop-up.
Instruments
launches and asks you to select a Trace Template. Choose iOS Simulator >
Leaks and then click Profile. Instruments opens a new profiling window,
launches the application in the simulator, and starts running. Click the Stop
button at the top-left of the Instruments window. There are some adjustments
you’ll want to make.
In
the left-hand column, under the individual Instruments traces, you’ll see an
item labeled “Allocations.” It is just below a slider and just above the
Heapshot Analysis. This is a pop-up, as indicated by the arrows to its right.
Use the pop-up to change from Allocations to Leaks.
With
Leaks selected, the first item is now Snapshots. Change the Snapshot Interval
from 10 seconds to 1. This lets you see updates in “real” time; even so, be
patient. Instruments detects leaks during its snapshots, with a slight lag
after performing the snapshot.
You
are now ready to start a fresh trace. Click Record. The application relaunches
in the simulator. With Instruments and the simulator both running, click one of
the two buttons in the title bar to leak memory:
- The
CF Bridging button leaks a simple 16-byte
NSArray
. - The
Retain Cycle button leaks two 16-byte
NSArray
objects that
are connected to each other via a retain cycle, for a total of 32 bytes.
Memory
leaks appear in Instruments as orange markers, scaled to the size of the leaks.
The Leaked Blocks pane appears at the bottom of the window, as shown in Figure 3-13, once you click the Leaks trace row
at the top of the window.
Figure 3-13
Instruments tracks leaks created by memory blocks that cannot be addressed or
recovered by your code.
The
trace shown in Figure 3-13 presents two leak
events. The first orange marker corresponds to tapping the Retain Cycle button;
the second to CF Bridging. The responsible frame for the first leak is shown to
be the leakArrayRetainCycle
method. A stack trace
appears in the extended detail pane on the right side of the view. This pane is
shown or hidden using the rightmost of the three View buttons at the top
toolbar of the Instruments window. My “Hello World” code is noted to be the
responsible library for both of the leaks, allowing me to further recognize
that the leaked memory originated in my code.
Note
-
When working with possible retain cycles, use the jump bar in the center of the
window (the quartered square followed by the word “Leaks” in
Figure 3-13) to choose Cycles. This is a
feature that Apple is still evolving. During the time this book was being
written (that is, the beta period), it functioned less and crashed more.
Hopefully Apple will finish refining this potentially valuable feedback before
the iOS 5 beta goes golden.
Recipe
3-1 Creating Programmatic Leaks
- (void) leakArrayRetainCycle {
NSMutableArray *array1 = [NSMutableArray array];
NSMutableArray *array2 = [NSMutableArray array];
[array1 addObject:array2];
[array2 addObject:array1];
}
- (void) leakArrayCFBridge
{
NSArray *array = [NSArray arrayWithObjects:
@"Hello", @"World", nil];
CFArrayRef leakyRef = (__bridge_retained CFArrayRef) array;
leakyRef = NULL;
}
Get
This Recipe’s Code - To get the code used for this recipe, go to
https://github.com/erica/iOS-5-Cookbook,
or if you've downloaded the disk image containing all the sample code from the
book, go to the folder for Chapter 3 and open the project for this recipe.
Recipe:
Using Instruments to Monitor Cached Object Allocations
When
you load too much data at once, you can also run short of memory. Holding onto
everything in your program when you are using memory-intense resources such as
images, audio, or PDFs may cause problems. A strategy called caching
lets you delay loads until resources are actually needed and release that
memory when the system needs it.
The
simplest approach involves building a cache from an NSMutableDictionary
object. A
basic object cache works like this: When queried, the cache checks to see
whether the requested object has already been loaded. If it has not, the cache
sends out a load request based on the object name. The object load method might
retrieve data locally or from the Web. After the data is loaded, the cache
stores the new information in memory for quick recall.
This
code performs the first part of a cache’s duties. It delays loading new data
into memory until that data is specifically requested. (In real life, you
probably want to type your data and return objects of a particular class rather
than use the generic id
type.)
- (id) retrieveObjectNamed: (NSString *) someKey {
id object = [self.myCache objectForKey:someKey];
if (!object)
{
object = [self loadObjectNamed:someKey];
[self.myCache setObject:object forKey:someKey];
}
return object;
}
The
second duty of a cache is to clear itself when the application encounters a
low-memory condition. With a dictionary-based cache, all you have to do is
remove the objects. When the next retrieval request arrives, the cache can
reload the requested object.
- (void) respondToMemoryWarning
{
[self.myCache removeAllObjects];
}
Combining
the delayed loads with the memory-triggered clearing allows a cache to operate
in a memory-friendly manner. Once objects are loaded into memory, they can be
used and reused without loading delays. However, when memory is tight, the cache
does its part to free up resources that are needed to keep the application
running.
Simulating
Low-Memory Conditions
One
feature of the simulator allows you to test how your application responds to
low-memory conditions. Selecting Hardware > Simulate Memory Warning sends
calls to your application delegate and view controllers, asking them to release
unneeded memory. Instruments, which lets you view memory allocations in real
time, can monitor those releases. It ensures that your application handles things
properly when warnings occur. With Instruments, you can test memory strategies
such as caches, discussed earlier in this chapter.
Recipe
3-2 creates a basic object cache. Rather than retrieve data from the Web or
from files, this cache builds empty NSData
objects to
simulate a real-world use case. When memory warnings arrive, as shown in Figure 3-14, the cache responds by releasing
its data.
Figure 3-14
Instruments helps monitor object allocations, letting you test your release
strategies during memory warnings.
The
stair-step pattern shown here represents four memory allocations created by
pressing the Consume button while using Instrument’s Allocation profiler.
After, the simulator issued a memory warning. In response, the cache did its
job by releasing the images it had stored. The memory then jumped back down to
its previous levels.
Instruments
lets you save your trace data, showing the application’s performance over time.
Stop the trace and then choose File > Save to create a new trace file. By
comparing runs, you can evaluate changes in performance and memory management
between versions of your application.
Some
SDK objects are automatically cached and released as needed. The UIImage imageNamed:
method retrieves and caches images in this
manner, as does the UINib nibWithNibName:bundle:
, which
preloads NIBs into a memory cache for faster loading. When memory grows low,
these classes empty their caches to free up that memory for other use.
Recipe 3-2 Object Cache Demo
@implementation ObjectCache
@synthesize myCache, allocationSize;
{
return [[ObjectCache alloc] init];
}
- (id) loadObjectNamed: (NSString *) someKey
{
if (!allocationSize)
allocationSize = 1024 * 1024;
char *foo = malloc(allocationSize);
NSData *data = [NSData dataWithBytes:foo length:allocationSize];
free(foo);
return data;
}
- (id) retrieveObjectNamed: (NSString *) someKey
{
if (!myCache)
self.myCache = [NSMutableDictionary dictionary];
id object = [myCache objectForKey:someKey];
if (!object)
{
if ((object = [self loadObjectNamed:someKey]))
[myCache setObject:object forKey:someKey];
} return object;
}
- (void) respondToMemoryWarning
{
[myCache removeAllObjects];
}
@end
Get
This Recipe’s Code - To get the code used for this recipe, go to
https://github.com/erica/iOS-5-Cookbook,
or if you've downloaded the disk image containing all the sample code from the
book, go to the folder for Chapter 3 and open the project for this recipe.
Analyzing
Your Code
The
LLVM/Clang static analyzer automatically helps detect bugs in Objective-C
programs. It’s a terrific tool for finding memory leaks and other issues,
especially with Core Foundation and MRR code. In Xcode, choose Product >
Analyze (Command-Control-B). The issue markers shown in Figure 3-15 guide you through all suspected
leaks and other potential problems. Use the Issue Navigator pane to dive into
each issue and walk through the logic that leads the analyzer to raise a flag
of concern.
Figure 3-15
The Clang static analyzer creates bug reports for source code and embeds them
into your Xcode editor window. Clang is useful for both MRR (as shown here) and
ARC and provides reports specific to each compilation style.
Issues
found by the static analyzer are not necessarily bugs. It’s possible to write
valid code that Clang identifies as incorrect. Always critically evaluate all
reported issues before making any changes to your code.
From
Xcode to Device: The Organizer Interface
Choose
Window > Organizer (Command-Shift-2) to open the Xcode Organizer window
shown in Figure 3-16. This window forms the
control hub for access between your development computer and your iOS testbed.
It allows you to manage your credentials, add and remove applications, examine
crash logs, and snap screenshots of your unit while testing your application.
Figure 3-16
Xcode’s Organizer window provides a central hub for managing your devices,
certificates, and provisions.
The
Organizer consists of two primary sections, the Library and the Devices, which
have overlapping functionality. The library offers what is, basically, a merged
inbox of device logs, provisioning profiles, and screenshots. These are broken
out on a per-device basis in the Devices section.
In
addition, the library has a Developer Profile section for organizing your
developer certificates and a Software Images section for managing firmware
bundles. The Devices list adds per-device consoles and per-device application
management.
Devices
The
Devices list shows the name and status of those devices you’ve authorized as
development platforms. The indicators to the right of each name show whether
the device is attached (green light) or not (white light). A blank to the right
of the device name indicates a unit that has not been set up for development or
that has been “ignored”—that is, removed from the active list. An amber light
appears when a device has just been attached. Should the light remain amber
colored, you may have encountered a connection problem. This may be due to
iTunes syncing, and the unit is not yet available, or there may be a problem
connecting with the onboard services, in which case a reboot of your iOS device
usually resolves any outstanding issues.
A
disclosure button appears to the left of each device, offering access to device
information specific to that device. The items you find here mirror many of
those listed in the Library section of the Organizer, including device logs,
screenshots, and provisioning profiles. In addition, you have access to the
device console and an application list.
Summary
Selecting
a device name offers an overview of that device, including the capacity, serial
number, and identifier of your unit. Here is also where you can load the latest
firmware onto a device. Select a firmware version from the software pop-up and
click Restore. Other items on this screen include overviews of current
provisions, applications, device logs, and screenshots.
Be
warned. Device downgrades are not always possible when you’ve upgraded to a
newer (especially beta) iOS version. Downgrades must be authorized by Apple’s
signature servers, even when you have stored the older firmware locally on your
computer. These servers allow Apple to control which older firmware they will
and will not allow to be installed, essentially providing them with a rolling
firmware recall system that disallows older firmware over time.
Provisioning
Profiles
Each
developer license allows you to provision your personal or corporate iOS
devices for testing. The Provisioning list shows a list of application
provisions available to your unit. You can add or delete provisions from this
screen.
Provisions
determine which applications may or may not be run on the device. As a rule,
only development and ad hoc distribution provisions are listed here, which
makes sense. Distribution provisions are used to sign applications for the App
Store, not for any specific device.
Device
Logs
Get
direct access to your crash logs by selecting a particular crash (labeled with
the application name and the date and time of the crash) from the scrolling
list on this screen. The crash details, including a stack trace, thread
information, exception types, and so forth, appear in the right-hand pane. You
can import and export logs using the buttons on this screen.
In
addition to crash logs that you generate yourself, you can also retrieve crash
reports from users from their home computer and from iTunes Connect. The iPhone
automatically syncs crash reports to computers when units back up to iTunes.
These reports are stored in different locations depending on the platform used
to sync the device:
- Mac
OS X—/Users/UserName/Library/Logs/CrashReporter/MobileDevice/
DeviceName
- Windows
XP—C:\Documents
and Settings\UserName\Application Data\Apple
Computer\Logs\CrashReporter\MobileDevice\DeviceName
- Windows
Vista—C:\Users\UserName\AppData\Roaming\Apple
Computer\Logs\CrashReporter\MobileDevice\DeviceName
iTunes
Connect collects crash log data from your App Store users and makes it
available to you. Download reports by selecting Manage Your Applications >
App Details > View Crash Report for any application. There you find a list
of the most frequent crash types and Download Report buttons for each type.
Copy
reports into the Mac OS X crash reporter folder and they load directly into the
Organizer. Make sure to load them into the device folder for the currently
selected device. The reports appear in LIBRARY > Device Logs.
Once
in the Organizer, Xcode uses the application binary and .dSYM file to replace
the hexadecimal addresses normally supplied by the report with function and
method names. This process is called “symbolication.” You don’t have to
manually locate these items; Xcode uses Spotlight and the application’s unique
identifier (UID) to locate the original binary and .dSYM files so long as they
exist somewhere in your home folder. Xcode’s archive feature offers the best
way to keep these materials together and persistently available.
As
with crash logs in the Organizer, the reports from users provide a stack trace
that you can load into Xcode to detect where errors occurred. The trace always
appears in reverse chronological order, so the first items in the list were the
last ones executed.
In
addition to showing you where the application crashed, Crash Reports also tell
you why they crashed. The most common cause is EXC_BAD_ACCESS
, which can be
generated by accessing unmapped memory (KERN_INVALID_ADDRESS
) or trying to
write to read-only memory (KERN_PROTECTION_FAILURE
).
Other
essential items in the crash report include the OS version of the crash and the
version of the application that crashed. Users do not always update software to
the latest release, so it’s important to distinguish which crashes arose from
earlier, now potentially fixed, versions.
Note
-
See Apple Technical Note TN2151 for more details about iOS crash reporting.
Applications
Each
device offers a browseable list of installed applications. Use the – button to
remove selected applications. To install an application, drag it onto the list
or use the + button to browse for it. Make sure your application is compiled
for iOS and that the device is provisioned to run that application. If you
self-sign an application and install it to a device—the how-to process for
doing so is described later in this chapter—your application uses your team
provision. When added, applications immediately sync over to the device.
Applications installed from the App Store do not appear in the application list
any more, the way they did in Xcode 3.
To
download the data associated with an application, click the Download button to
the right of its name. Choose a destination and click Save. Xcode builds an
archive bundle and populates it with the contents of the sandbox—namely the
Documents, Library, and tmp directories. Xcode also adds the folder to the
Projects and Sources list, where you can browse the contents directly from the
Organizer.
You
can reverse this process and add edited sandboxes back to the device. Locate
the bundle you created. Drop new items into any of the enclosed subfolders and
then drag the entire folder back onto the application name at the bottom of the
Summary pane. Xcode reads the new items and instantly transfers them to the
device. This is a great way to prepopulate your sandbox with test material.
Console
Use
the console to view system messages from your connected units. This screen
shows NSLog()
calls and other
messages sent to stderr
(standard error
output) as you’re running software on the tethered iPhone. You need not be
using Xcode’s debugger to do this. The console listens in to any application
currently running on the device.
In
addition to the debugging messages you add to your iPhone applications, you
also see system notices, device information, and debugging calls from Apple’s
system software. It can be viewed as basically a text-based mess, but there’s a
lot of valuable information you can gain. Click Save Log As to write the
console contents out to disk or click Clear to empty the Console backlog.
Screenshots
Snapshot
your tethered iPhone’s screen by clicking the New Screenshot button on the
Screenshot display. The screenshot feature takes a picture of whatever is
running on the iPhone, whether or not your applications are open. So you can
access shots of Apple’s built-in software and any other applications running on
the iPhone.
Once
snapped, images can be dragged onto the desktop or saved as an open project’s
new Default.png image (“Save as Launch Image”). Archival shots appear in a
library on the left side of the window. To delete a screenshot, select one and
press the Delete key to permanently remove it. Other features on this screen
allow you to export images and compare images to highlight differences between
separate shots.
Note
-
Screenshots are stored in your home Library/Application
Support/Developer/Shared/Xcode/Screenshots folder.
Building
for the iOS Device
Building
for and testing in the simulator takes you only so far. The end goal of iOS
development is to create applications that run on actual devices. There are
three ways to do so: building for development, for App Store distribution, and
for ad hoc deployment. These three, respectively, allow you to test locally on
your device, to build for the App Store, and to build test and review versions
of your applications that run on up to 100 registered devices. Chapter 1
introduced mobile provisions and showed how to create these in the Apple iOS
Developer Program portal. Now it’s time to put these to use and deploy a
program to the device itself.
Using
a Development Provision
A
development provision is a prerequisite for iOS deployment. Your team
provisioning profile is automatically created and managed by Xcode. You can
also create your own wildcard dev provision at Apple’s provisioning portal if
desired, but it’s not really necessary anymore for basic development now that
Xcode has introduced the team profile.
The
Xcode Organizer (Command-Shift-2) provides the hub around which you can manage
your provisions, certificates, and devices. Figure 3-16 shows the Organizer
window with the Provisioning Profiles organizer displayed.
To
enable automatic device provisioning, check the Automatic Device Provisioning
box shown at the bottom of Figure 3-16. This option allows you to register new
devices with Apple directly from the Organizer. Xcode automatically uploads
device information to the developer portal and downloads an updated provision
that adds the new device.
For
the times you need to add provisions to Xcode directly, click the Import button
at the bottom of the window. Navigate to the provision, select it, and click
Open. The Provisioning Profiles organizer also allows you to view the provision
creation and expiration dates.
The
Developer Profile organizer lists all your iOS and Mac developer certificates
for both development and distribution. The Import and Export buttons at the
bottom of this organizer allow you to package up your developer identities for
easy secure transfer to other computers. These certificates are stored in your
system keychain. You may want to review your keychain and ensure that the WWDR
(Worldwide Developer Relations) certificate is available for use. It is not
listed in the Developer Profile organizer directly.
During
compilation, Xcode matches the currently selected provision against your
keychain identities. These must match or Xcode will be unable to finish
compiling and signing your application. To check your certificates, open
Keychain Access (from /Applications/Utilities) and type developer
in the search box on the top right. You should see, at a minimum, your Apple
Worldwide Developer Relations certifications authority and one labeled iPhone
Developer followed by your (company) name.
Enable
a Device
Tether
a device that you wish to test on to your computer. You may need to wait for it
to finish syncing in iTunes, first. For serious development, you can open
Preferences in iTunes (Command-,), select the Devices tab, and check Prevent
iPods, iPhones, and iPads from Syncing Automatically. Click OK to apply your
new settings.
You
can add devices to your account directly from Xcode. Select a device in the
Xcode organizer (Window > Organizer, or Command-Shift-2). Right-click (or
Control-click) its name and choose Add Device to Provisioning Portal (see Figure 3-17).
Figure 3-17
Use the Device organizer to add devices to the iOS provisioning portal.
Xcode
will prompt you to log in to the iPhone provisioning portal with your program
credentials. Once you’re authenticated, it will upload the device details and
generate (or regenerate) your team provisioning profile.
First-time
developers are sometimes scared that their device will be locked in some
“development mode,” mostly due to Apple’s standard warning text; in reality, I
have heard of no long-lasting issues. Regardless, do your homework before
committing your device as a development unit. Read through the latest SDK
release notes for details.
Inspect
Your Application Identifier
Your
project application identifier can be inspected and updated as needed. Select
the project in the Project Navigator and choose TARGETS > Project Name.
Select the Info tab to reveal the Custom iOS Target Properties, as shown in Figure 3-18. The application identifier can be
set manually by editing the Bundle Identifier field. Xcode defaults to using
your RFC 1034 reverse domain root identity followed by the product name.
Figure 3-18
The Info tab allows you to edit the Bundle identifier.
Your
team development provision automatically matches all projects; its registered
identifier is a single wildcard asterisk (*). Other provisions may or may not
match the application identifier you are using. If you registered a wildcard
application identifier of, say, com.sadun.* and used that to generate a
provisioning profile, it would match com.sadun.helloworld or com.sadun.testing,
for example, but not helloworld or com.mycompany.helloworld.
Set
Your Device and Code Signing Identity
After
checking your identifier, click PROJECT > project name > Build
Settings. Enter device into the search field at the top-right
of the Build Settings pane. This should match one setting: Targeted Device
Family. Use this pop-up to select which devices you wish to compile for:
iPhone, iPad, or iPhone/iPad. This last choice allows you to build a universal
application that can install and run on both devices, taking advantage of each
system’s native geometry.
Next,
confirm your code-signing identity. Make sure you are looking at All settings
(not just Basic ones). Enter signing in the top-right search
field. Select your identity from the pop-up lists that appear to the right of
each build type. As you start to accumulate provisions and identities, the list
of options can become long, especially if you get involved in beta testing for
third parties.
The
two Automatic Profile Selectors automatically pick the first matching profile.
I am paranoid enough to always inspect both the certificate name and the
profile identity just above that name before choosing a profile. Apple
recommends using automatic selection.
Set
Your Base and Deployment SDK Targets
The
Base SDK target setting specifies what version of the SDK is used to compile
your application. Open PROJECT > project name > Build Settings
and locate Base SDK at the top of the list. As a rule, you may keep this option
set to Latest iOS. It will automatically match the most recently installed SDK.
That means your code will not fail compilation if it uses the newest introduced
APIs. The compiler will handle these correctly. However, your code may still
fail at execution if new APIs are called on devices whose firmware does not yet
support them—for example, calling a 5.1 API on a 4.3 device. That’s a problem
you handle not with the Base SDK, but with the deployment target (see Figure 3-19).
Figure 3-19
The Base SDK sets the iOS version used to compile your applications. The armv7
architecture is currently available on the iPhone 3GS and newer, the iPod touch
3G and newer, and all iPads.
Set
your deployment target in TARGET > project name > Summary > iOS
Application Target in the first section of the Summary view. This pop-up (see Figure 3-20) specifies the earliest device that
you wish to allow your application to install to.
Figure 3-20
Deployment Target sets the earliest iOS version that is permitted to run your
application.
If
you compile in 5.x and deploy to 4.x, you can use 5.x
calls in your code but you will need to use runtime checks to ensure that you
do not call APIs on platforms that do not support them and weak linking for any
frameworks that aren’t found on the deployment target. Both runtime and
compile-time code checks are covered later in this chapter. Setting the
deployment target to the base SDK target ensures that you will never have to
make any runtime API checks but limits your audience to only those customers
who have updated their units to the latest firmware. The more you support
earlier firmware releases, especially within the same iOS release family, such
as 4.x, 5.x, and so forth, the more you increase your
potential user base.
Compile
and Run the Hello World Application
Finally,
it’s time to test Hello World on an actual iPhone, iPod touch, or iPad. Before
you compile, you must tell Xcode to build for the iOS device’s ARM architecture
rather than the simulator’s Intel one. Locate the scheme pop-up at the top-left
of your workspace’s toolbar and open it. It should look something like Figure 3-21. Device names appear at the top of
the list, simulator choices at the bottom. Xcode highlights devices using
firmware matching the deployment target but that are earlier than the Base SDK.
Select a device.
Figure 3-21
Xcode makes a point of highlighting devices whose firmware lags behind the Base
SDK. Older firmware installations form a vital component of your testing base
to help ensure your code works on all valid deployment targets.
Choose
Product > Run (Command-R) or click the Run button (it looks like a Play
button) at the left of the workspace’s toolbar. Assuming you have followed the
directions earlier in this chapter properly, the Hello World project should
compile without error, copy over to the iPhone, and start running.
If
the project warns you about the absence of an attached provisioned device, open
the Xcode Organizer window and verify that the dot next to your device is
green. If this is not the case, you may need to restart Xcode or reboot your
device or your computer.
Signing
Compiled Applications
You
can sign already compiled applications at the command line using a simple shell
script. This works for applications built for development. Signing applications
directly helps developers share applications outside of ad hoc channels.
#! /bin/bash export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/ bin/codesign_allocate codesign -f -s "iPhone Developer" $1.app
If
you use several iPhone Developer profiles in your keychain, you may need to
adapt this script so that it matches only one of those; otherwise, codesign
complains about ambiguous matching.
I
personally use this approach to distribute test versions of the sample code
from this book. Using developer code-signing skips the hassles of ad hoc
distribution, allowing a rapid testing turn around without using up valuable
device slots.
Detecting
Simulator Builds with Compile-Time Checks
Xcode
directives issue instructions to the compiler that can detect the platform
you’re building for. This lets you customize your application to safely take
advantage of device-only features when they’re available. Adding #if
statements to your code lets you block or reveal functionality based on these
options. To detect if your code is compiled for the simulator or for an iOS
device, use a compile-time check:
#if TARGET_IPHONE_SIMULATOR Code specific to simulator #else Code specific to iPhone #endif
Performing
Runtime Compatibility Checks
There
is a real and measurable adoption lag among iOS device users. To sell your
application to the greatest number of customers, do not build for any SDK
higher than your lowest desired customer. Use common sense when picking that
SDK. You may find it best to support the most recent firmware dot release that
lags a few weeks or months behind the latest iOS update, or you may want to
extend support to all versions of the current iOS firmware.
The
hardest decisions come when iOS moves forward to a new version. That’s when the
adoption rate slows down the most. The 3.x/4.x overlap lasted
for some time before developers gained confidence in moving forward to 4.x-only
releases. iOS 5 and its successors continue that challenge.
To
build for a range of possible deployment targets, set your Base SDK to the
highest version of the OS you want to target—usually the current SDK release.
Set your iOS deployment target to the lowest OS version you intend to build
for.
When
compiling to a deployment target that is earlier than your base SDK, you’ll
need to perform runtime checks for any classes or API calls that might not yet
have been introduced to a given firmware platform. For example, an iOS
5-introduced API call will not be available on an iOS 4.2 installation. The
following tests allow you to check at runtime for classes and methods that may
or may not be available depending on the deployment platform:
- Check
platform geometry—Introduced in iOS 3.2, the idiom check lets
you determine if your code is running on an iPhone-like unit (iPhone, iPod
touch) or on an iPad. I have not included extensions here to see whether the
check itself is implemented simply because I cannot recommend deploying to
pre-3.2 platforms anymore. As of the Summer of 2011, 3.x platforms
made up only about 5% of all iOS installations. Pre-3.2 installs were a
vanishingly small percentage of that.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) . . .
Check
deployment platform—Use the model property of the UIDevice class
to determine whether the unit is running on an @"iPhone", if
([[UIDevice currentDevice].model isEqualToString:@"iPad"]) . . .Check
system prefix—It’s not the best way to approach coding (checking
classes and instances directly is far more reliable), but you can
check the current system version directly.
if ([[[UIDevice currentDevice] systemVersion] hasPrefix:@"5."]) . . .
Check
for properties using key-value coding—You can determine
whether an object offers a value for a given key within the current scope, which
allows you to test for properties.
UILabel *label = (UILabel *)[cell valueForKey:@"textLabel"]; if (label) [label setText:celltext];
Check
for class existence—If a class may not exist on a given
deployment target, use NSClassFromString()
to test
whether the class can be produced from its name. Pass it an NSString
, such as the following:
if (NSClassFromString(@"NSAttributedString")) . . .
Check
for function existence—You can test for functions before attempting
to call them.
if(&UIGraphicsBeginImageContextWithOptions != NULL) . . .
Check
for selector compliance—You can test objects to see whether they
respond to specific selectors. When newer APIS are supported, objects will
report that they respond to those selectors, letting you call them without
crashing the program. You may generate compile-time warnings about
unimplemented selectors unless you use workarounds such as performSelector:withObject:.
If you really want to go hard core,
you can build NSInvocation
instances directly,
as discussed in Chapter 3.
if ([cell respondsToSelector:)]) . . .
Pragma
Marks
Pragma
marks organize your source code by adding bookmarks into the method list pop-up
button at the top of each Xcode window. This list shows all the methods and
functions available in the current document. Adding pragma marks lets you group
related items together, as shown in Figure 3-22.
By clicking these labels from the drop-down list, you can jump to a section of
your file (for example, to Utility
or RAOP
)
as well as to a specific method (such as -hexStringFromBytes:
).
Figure 3-22
Use pragma marks to organize your method and function list.
To
create a new bookmark, add a pragma mark definition to your code. To replicate
the first group in Figure 3-22, for example,
add the following:
#pragma mark Class
You
can also add a separation line with a single dash. This uses a shortcut to add
a spacer plus a mark:
#pragma mark –
or
#pragma mark – Marker Title
The
marks have no functionality and otherwise do not affect your code. They are
simply organizational tools you choose to use or not.
Collapsing
Methods
When
you need to see more than one part of your code at once, Xcode lets you close
and open method groups. Place your mouse in the gutter directly to the left of
any method. A pair of disclosure triangles appears. Click a triangle, and Xcode
collapses the code for that method, as shown in Figure
3-23. The ellipsis indicates the collapsed method. Click the disclosure
triangle, and Xcode reveals the collapsed code. You can also collapse any
compound statement.
Figure 3-23
Xcode lets you collapse individual methods and functions. This allows you to
see parts of your program that normally would not fit onscreen together.
Preparing
for Distribution
Building
for distribution means creating a version of your application that can be
submitted to Apple for sale in the App Store. Before you begin submitting, know
how to clean up builds, how to edit and use schemes, and how create an archive
of your application. You want to compile for the App Store with precision.
Cleaning first, then compiling for distribution helps ensure that your
applications will upload properly. Archiving produces an application bundling
that can be shared and submitted. The section covers these skills and others
used with distribution compiles.
Locating
and Cleaning Builds
Xcode
4 uses a new approach to build code and store built products. In Xcode 3,
compiled code was added to a “build” subfolder in your project folder. In Xcode
4, applications are created in your home library by default, in
~/Library/Developer/Xcode/DerivedData. You can locate the built product by
selecting it in Project Navigator in the Products group. Right-click the
application and choose Show in Finder. Project Archives, which are used for
building products that are shared with others or submitted to the App Store,
are stored in ~/Library/Developer/Xcode/ Archives.
Cleaning
your builds forces every part of your project to be recompiled from scratch.
Performing a clean operation also ensures that your project build contains
current versions of your project assets, including images and sounds. You can
force a clean by choosing Product > Clean (Command-Shift-K).
Apple
recommends cleaning before compiling any application for App Store review, and
it’s a good habit to get into.
Using
Schemes and Actions
In
Xcode, schemes store project build settings. They specify what targets to
build, what configuration options to apply, and how the executable environment
will be set up. Actions are individual tasks that you can perform to create
builds as well as to test, profile, analyze, and archive your application.
Each
scheme consists of a project and a destination. Figure
3-24 shows the scheme pop-up for the Hello World project from this chapter.
Access this pop-up by selecting Hello World to the right of the Run button.
This is a funny kind of pop-up in that it’s actually split. Clicking to the
left or the right of the embedded chevron provides two slightly different
menus.
Figure 3-24
The scheme pop-up menu consists of schemes and their run destinations, followed
by management options.
Clicking
the left produces the pop-up shown in Figure
3-24. This pop-up includes a list of schemes (just one here) and their
possible run destinations. Here, destinations include the device and four
simulator styles (iPhone and iPad, for iOS 4.3 and iOS 5.0). Following the
scheme list is a menu line followed by three options to edit, create, and
manage schemes.
Clicking
the right shows only the destination submenu, allowing you to pick a
destination for the current scheme. Destinations include any provisioned and
development-enabled iOS devices as well as all possible simulator choices for
your deployment build settings.
Note
-
The plural of scheme in Xcode is schemes, not schema or schemata. As iOS
developer Nate True puts it, “It’s schemata non grata” in Xcode.
With
your scheme selected, choose Edit Scheme from the pop-up menu to see a list of
available actions. Figure 3-25 shows the actions associated with the Hello
World scheme from Figure 3-24. Each action
represents an individual development task. They include the following:
- Build—Building the
code
- Run—Running the
compiled code on a device or in the simulator
- Test—Using Xcode
unit test tools that help stress application features
- Profile—Running the
code with live sampling using Instruments
- Analyze—Applying the
static analyzer to unresolved issues
- Archive—Preparing the
application for sharing or submission to the App Store
Use
this scheme editor to customize how each action works in Xcode. For example, in
the Run action shown in Figure 3-25, the
debugger is set to LLDB. You can easily change this to GDB by selecting it from
the pop-up.
Figure 3-25
The actions list for a scheme offer a set of tasks that may need to be
performed during the creation of an application.
You’ve
already seen the action menu in the Instruments walkthrough earlier in this
chapter. Access it by clicking and holding the Run menu at the top-left corner
of the Xcode window. Select the action you want to perform from the pop-up. The
Run button updates to show the new action item.
Adding
Build Configurations
Build
configurations allow you to specify how your application should be built. They
act as a quick reference to the way you want to have everything set up, so you
can be ready to compile for your device or for the App Store just by selecting
a configuration. They also are useful for adding instrumentation and
conditional compilation. Standard Xcode projects offer Debug and Release
configurations. You may want to create a few others, such as one for ad hoc
distribution.
Configurations
are created and managed on the PROJECT > project name > Info
screen in the Configurations section (see Figure
3-26). Assuming you’ve been following along in this chapter, you have
already set up the HelloWorld project and edited its debug build settings. It
uses your team wildcard provision to sign the application. Instead of editing
the build settings each time you want to switch the signing provision, you can
create a new configuration instead. Typical configuration options include which
architectures you wish to build for and your default code-signing identity.
Figure 3-26
Use the Info > Configurations pane to create new configurations so you can
build with preset options such as signing identities.
In
the following sections, you’ll read about adding an ad hoc configuration to
your project. This is really for example purposes only—because I cannot really
think of many other ways you’d want to change build settings for ad hoc versus
App Store and because you can pick your signing identity in the Organizer when
creating bundles for both destinations. Adapt this example and its steps for
your real-world requirements.
Note
-
You can distinguish your ad hoc configuration build by using a different bundle
ID, product name, or by adding extra alerts, to make it easier to run along the
App Store version. Use #ifdef
directives to
distinguish ad hoc code changes.
About
Ad Hoc Distribution
Apple
allows you to distribute your applications outside the App Store via ad hoc
distribution. With ad hoc, you can send your applications to up to 100
registered devices and run those applications using a special kind of mobile
provision that allows the applications to execute under the iPhone’s FairPlay
restrictions. Ad hoc distribution is especially useful for beta testing and for
submitting review applications to news sites and magazines.
The
ad hoc process starts with registering devices. Use the iPhone Developer
Program portal to add device identifiers (Program Portal, Devices) and names to
your account. Recover these identifiers from the iPhone directly (use the UIDevice
class), from Xcode’s Organizer (copy the identifier from
the overview tab), from iTunes (click on Serial Number in the iPhone’s Summary
tab), or via the free Ad Hoc Helper application available from iTunes. Enter
the identifier and a unique username.
To
create a new ad hoc configuration, create a new provision at the iOS portal.
Select Program Portal > Provisioning > Distribution. Click Add Profile.
Select Ad Hoc, enter a profile name, your standard wildcard application
identifier (for example, com.yourname.*), and select the device or devices to
deploy on. Don’t forget to check your identity and then click Submit and wait
for Apple to build the new mobile provision. Download the provision file and
drop it onto the Xcode application icon.
With
your new provision on hand, duplicate the Release configuration. Xcode creates
a copy and opens a text entry field for its name. Edit the name from Release
copy to Ad Hoc.
Next,
click the Build Settings tab and locate the Code Signing section. Assign your
new ad hoc provision to your ad hoc configuration. Use the pop-up to the right
of Any iOS SDK. The selected provision then appears in the Code Signing
Identity list, as shown in Figure 3-27.
Figure 3-27
New configurations appear separately in the Code Signing section of your build
settings.
To
finish, choose your new build configuration in the Archive action section of
the Scheme editor.
Note
-
In addition to adding new configurations by hand, you can also use build
configuration files that contain setting definitions in text format. Create
these files by selecting File > New > New File > Other >
Configuration Settings. You can read more about creating configuration files in
Apple’s Xcode Build System Guide.
Building
Ad-Hoc Packages
- When you’re ready to
share your app with members of your ad hoc list, follow these steps:
- If you wish to use a
custom compiler scheme, choose Edit Scheme from the Scheme pop-up at the top of
the Xcode window. Select Archive and set your Build Configuration as desired.
Click OK. If you want to use the default compiler scheme, you may skip this
step.
- Choose Product >
Archive from the main Xcode menu.
- Wait for Xcode to
work. The Organizer will open when it is finished, displaying the Archives tab.
This screen allows you to review, manage, and use archived copies of your
applications. You can also add free-form comments to each archive—a very handy
feature—and a status line lets you track when archives have been successfully
submitted to the App Store.
- For ad hoc
distribution, click Share. Choose iOS App Store Package (.ipa) as your
destination.
- Choose your ad hoc
provision from the Identity pop-up and click Next.
- Specify the name of
your new package (for example, HelloApp) and where to save it. Click Save.
After
following these steps, you can now e-mail the newly built .ipa file to members
of your beta list or post it to a central site for download.
The
.ipa bundle you built is actually a renamed ZIP file. If you extract it and
look inside the Payload folder, you’ll discover the compiled application
bundle. This contains an embedded mobile provision that enumerates all the
device IDs included in the ad hoc provisioning.
<string>Wildcard Ad Hoc </string> <key>ProvisionedDevices</key>
Note
-
TestFlight offers over-the-air ad hoc management that has become quite popular
in the developer community. Visit testflightapp.com
for details.
Over-the-Air
Ad Hoc Distribution
You
can distribute Ad Hoc ipa files over the air by creating links to a simple
webpage. The itms-services: URL scheme, when pointing to an application
manifest property list allows your users to install apps wirelessly. You
provide the ipa and the manifest on the website. Here’s how you might link to
the manifest.
<a href="itms-services://?action=download-manifest&\ url=http://example.com/manifest.plist">Install App</a>
Make
sure your website is configured to support the following two MIME types.
application/octet-stream ipa text/xml plist
Building
a Manifest
The
manifest is an XML-based property list. It must contain six key/value pairs:
URL
—a fully-qualified URL pointing to the
ipa filedisplay-image
—a fully-qualified URL
pointing to a 57x57-pixel PNG icon used during download and installationfull-size-image
—a fully-qualified URL
pointing to a 512x512-pixel PNG (not JPEG!) image that represents the iTunes
appbundle-identifier
—the app’s standard
application identifier string, as specified in the app’s Info.plist filebundle-version
—the app’s current
bundle version string, as specified in the app’s Info.plist filetitle
—a human-readable
application name
In
addition to these required keys, you can specify an optional md5 hash for file
elements. Listing 3-3 shows a sample manifest provided by Apple.
Listing
3-3 Apple Sample Manifest
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict>
<!-- array of downloads. -->
<key>items</key>
<array>
<dict>
<!-- an array of assets to download -->
<key>assets</key>
<array>
<!-- software-package: the ipa to install. -->
<dict>
<!-- required. the asset kind. -->
<key>kind</key>
<string>software-package</string>
<!-- optional. md5 every n bytes. -->
<!-- will restart a chunk if md5 fails. -->
<key>md5-size</key>
<integer>10485760</integer>
<!-- optional. array of md5 hashes -->
<key>md5s</key>
<array>
<string>41fa64bb7a7cae5a46bfb45821ac8bba</string>
<string>51fa64bb7a7cae5a46bfb45821ac8bba</string>
</array>
<!-- required. the URL of the file to download. -->
<key>url</key>
<string>http:
</dict>
<!-- display-image: the icon to display during download .-->
<dict>
<key>kind</key>
<string>display-image</string>
<!-- optional. icon needs shine effect applied. -->
<key>needs-shine</key>
<true/>
<key>url</key>
<string>http:
</dict>
<!-- full-size-image: the large 512x512 icon used by iTunes. -->
<dict>
<key>kind</key>
<string>full-size-image</string>
<!-- optional. one md5 hash for the entire file. -->
<key>md5</key>
<string>61fa64bb7a7cae5a46bfb45821ac8bba</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>http:
</dict>
</array><key>metadata</key>
<dict>
<!-- required -->
<key>bundle-identifier</key>
<string>com.example.fooapp</string>
<!-- optional (software only) -->
<key>bundle-version</key>
<string>1.0</string>
<!-- required. the download kind. -->
<key>kind</key>
<string>software</string>
<!-- optional. displayed during download; -->
<!-- typically company name -->
<key>subtitle</key>
<string>Apple</string>
<!-- required. the title to display during the download. -->
<key>title</key>
<string>Example Corporate App</string>
</dict>
</dict>
</array>
</dict>
</plist>
Submitting
to the App Store
To
build your application in compliance with the App Store’s submission policies,
it must be signed by a valid distribution provision profile using an active
developer identity. The steps are very close to those you used to create an ad
hoc distribution, but you have additional bookkeeping that you must perform.
Make
sure you have at least one 512·512 PNG image on hand as well as at least one
screenshot for the next few steps. If you’re still not ready with final art,
you can upload placeholders and replace or delete them later as needed.
Start
by visiting the iOS portal and register your application identifier in the App
IDs tab of the portal. This takes just a second or two and requires a common
name (for example, “Collage”) and the identifier (for example,
com.sadun.Collage). This identifier should exactly match the one you use in
Xcode. Even though you usually sign your app with a general wildcard provision,
the application identifier you need for iTunes must be specific.
Head
over to iTunes Connect (iTunesConnect.apple.com).
Choose Manage Your Applications > Add New App > iOS App. Enter the
application name (it must be unique), the SKU number (it’s up to you how you
define this, but it must be unique to your account), and select your new
identifier from the Bundle ID pop-up. Be exact as possible on this screen and
do not use placeholders during this step. Make very sure you select
the proper identifier. Once set, it cannot be changed.
Enter
all your metadata—it can all be placeholders here—and set your two images.
iTunes Connect creates your new application page and adds a “Ready to Upload
Binary” button. When you click that button and declare your export encryption
compliance, you’re given instructions on how to upload your binary. Your
application state changes from Ready to Upload to Waiting for Upload. Click
Continue.
When
you use placeholders in your iPhone metadata, you now have as much time as you
need to edit that material. Just be sure you get your descriptions and art into
shape before uploading your application from Xcode. Your upload kicks
off the App Store review process. Do not waste Apple’s app reviewers’ time by
uploading your app until it’s ready to be reviewed.
Finally,
make sure you read Apple’s App Store submission guide, which walks you through
the process and its guidelines, which help explain what apps are and are not
suitable for the App Store.
Over-the-Air
Ad Hoc Distribution
You
can distribute Ad Hoc ipa files over the air by creating links to a simple
webpage. The itms-services: URL scheme, when pointing to an application
manifest property list allows your users to install apps wirelessly. You
provide the ipa and the manifest on the website. Here’s how you might link to
the manifest.
<a href="itms-services://?action=download-manifest&\ url=http://example.com/manifest.plist">Install App</a>
Make
sure your website is configured to support the following two MIME types.
application/octet-stream ipa text/xml plist
Building
a Manifest
The
manifest is an XML-based property list. It must contain six key/value pairs:
URL
—a fully-qualified URL pointing to the
ipa filedisplay-image
—a fully-qualified URL
pointing to a 57x57-pixel PNG icon used during download and installationfull-size-image
—a fully-qualified URL
pointing to a 512x512-pixel PNG (not JPEG!) image that represents the iTunes
appbundle-identifier
—the app’s standard
application identifier string, as specified in the app’s Info.plist filebundle-version
—the app’s current
bundle version string, as specified in the app’s Info.plist filetitle
—a human-readable
application name
In
addition to these required keys, you can specify an optional md5 hash for file
elements. Listing 3-3 shows a sample manifest provided by Apple.
Listing
3-3 Apple Sample Manifest
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <dict>
<!-- array of downloads. -->
<key>items</key>
<array>
<dict>
<!-- an array of assets to download -->
<key>assets</key>
<array>
<!-- software-package: the ipa to install. -->
<dict>
<!-- required. the asset kind. -->
<key>kind</key>
<string>software-package</string>
<!-- optional. md5 every n bytes. -->
<!-- will restart a chunk if md5 fails. -->
<key>md5-size</key>
<integer>10485760</integer>
<!-- optional. array of md5 hashes -->
<key>md5s</key>
<array>
<string>41fa64bb7a7cae5a46bfb45821ac8bba</string>
<string>51fa64bb7a7cae5a46bfb45821ac8bba</string>
</array>
<!-- required. the URL of the file to download. -->
<key>url</key>
<string>http:
</dict>
<!-- display-image: the icon to display during download .-->
<dict>
<key>kind</key>
<string>display-image</string>
<!-- optional. icon needs shine effect applied. -->
<key>needs-shine</key>
<true/>
<key>url</key>
<string>http:
</dict>
<!-- full-size-image: the large 512x512 icon used by iTunes. -->
<dict>
<key>kind</key>
<string>full-size-image</string>
<!-- optional. one md5 hash for the entire file. -->
<key>md5</key>
<string>61fa64bb7a7cae5a46bfb45821ac8bba</string>
<key>needs-shine</key>
<true/>
<key>url</key>
<string>http:
</dict>
</array><key>metadata</key>
<dict>
<!-- required -->
<key>bundle-identifier</key>
<string>com.example.fooapp</string>
<!-- optional (software only) -->
<key>bundle-version</key>
<string>1.0</string>
<!-- required. the download kind. -->
<key>kind</key>
<string>software</string>
<!-- optional. displayed during download; -->
<!-- typically company name -->
<key>subtitle</key>
<string>Apple</string>
<!-- required. the title to display during the download. -->
<key>title</key>
<string>Example Corporate App</string>
</dict>
</dict>
</array>
</dict>
</plist>
Submitting
to the App Store
To
build your application in compliance with the App Store’s submission policies,
it must be signed by a valid distribution provision profile using an active
developer identity. The steps are very close to those you used to create an ad
hoc distribution, but you have additional bookkeeping that you must perform.
Make
sure you have at least one 512·512 PNG image on hand as well as at least one
screenshot for the next few steps. If you’re still not ready with final art,
you can upload placeholders and replace or delete them later as needed.
Start
by visiting the iOS portal and register your application identifier in the App
IDs tab of the portal. This takes just a second or two and requires a common
name (for example, “Collage”) and the identifier (for example,
com.sadun.Collage). This identifier should exactly match the one you use in
Xcode. Even though you usually sign your app with a general wildcard provision,
the application identifier you need for iTunes must be specific.
Head
over to iTunes Connect (iTunesConnect.apple.com).
Choose Manage Your Applications > Add New App > iOS App. Enter the
application name (it must be unique), the SKU number (it’s up to you how you
define this, but it must be unique to your account), and select your new
identifier from the Bundle ID pop-up. Be exact as possible on this screen and
do not use placeholders during this step. Make very sure you select
the proper identifier. Once set, it cannot be changed.
Enter
all your metadata—it can all be placeholders here—and set your two images.
iTunes Connect creates your new application page and adds a “Ready to Upload
Binary” button. When you click that button and declare your export encryption
compliance, you’re given instructions on how to upload your binary. Your
application state changes from Ready to Upload to Waiting for Upload. Click
Continue.
When
you use placeholders in your iPhone metadata, you now have as much time as you
need to edit that material. Just be sure you get your descriptions and art into
shape before uploading your application from Xcode. Your upload kicks
off the App Store review process. Do not waste Apple’s app reviewers’ time by
uploading your app until it’s ready to be reviewed.
Finally,
make sure you read Apple’s App Store submission guide, which walks you through
the process and its guidelines, which help explain what apps are and are not
suitable for the App Store.
Note
-
Take special note of the Review Notes area in the Application Metadata. This is
your single line of human communication with Apple reviewers. Use this section
to explain any areas of confusion you think the reviewer may encounter. Offer
how-to procedures if needed and sample account credentials for testing your
application.
When
you are absolutely sure you’re ready to submit your application, follow these
steps:
- Review your iTunes
Connect metadata for clarity and correctness.
- Archive your
application (Product > Archive).
- In the Organizer,
click Submit.
- Enter your developer
login credentials and click Next.
- Select your
application from the top pop-up (see Figure 3-28).
Only applications that are “Waiting for Upload” appear in this list.
- Select your
distribution identity from bottom pop-up. Make sure it is your general
distribution identity and not an ad hoc distribution one! This is a common
mistake that usually results in an e-mail from iTunes asking you to re-submit
your application after it fails the code-signing check. Click Next.
- Wait as Xcode
validates and submits your application. When it is finished, the Status field
next to your application name updates to match the status of your submission.
Wait for an e-mail from iTunes saying that your application has changed state
to Waiting for Review.
Figure 3-28
Only apps that are “Waiting for Upload” are listed in the Organizer’s
submission screen. Make sure your identity is not set to an ad hoc profile,
also listed as iPhone Distribution. It’s a common error that lots of developers
make.
If
you encounter any trouble uploading, you may want to clean your project and
recompile from scratch. If you are unable to verify or submit your application,
try re-installing Xcode. Sometimes when you install beta versions of the SDK on
the same machine as your primary development Xcode SDK, those versions can
overwrite the tools you need to properly submit your applications to iTunes
Connect.
Note
-
Keep on top of your calendar. You must renew your developer membership yearly.
Your certificates all have expiration dates as well. When renewing your
developer and distribution certificates, you must reissue all your mobile
provisions. Throw away the old ones and create new ones with your updated
developer identity. Make sure to remove the outdated certificates from your
keychain when replacing them with the new ones.
Summary
This
chapter covered a lot of ground. From start to finish, you saw how to create,
compile, and debug Xcode projects. You were introduced to most of the major
Xcode components you’ll use on a day-to-day basis, and you read about many of
the different ways you can produce and run iPhone projects. Here are some
thoughts to take away from this chapter:
- Although
Xcode provides easy-to-use templates, think of them as a jumping-off point, not
an endpoint. You can customize and edit projects however you want.
- Interface
Builder makes it really easy to lay out views. Although, technically, you’re
producing the same method calls and property assignments as if you’d designed
by hand, IB’s elegant GUI transforms those design tasks into the visual domain,
which is a welcome place for many developers.
- Learning
to navigate through Xcode’s in-program reference documentation is an essential
part of becoming an iPhone developer. No one can keep all that information in
his or her head. The more you master the documentation interface, the better
you’ll be at finding the class, method, or property you need to move forward.
- Everything
changes. Subscribe to iOS documentation in Xcode and ensure that your
documentation remains as up to date as possible.
- Xcode’s
built-in debugger and Instruments tools help you fix bugs faster than trying to
figure out everything by hand. The tools may seem complex at first but are well
worth mastering for day-to-day development.
- Get
to know and love the Organizer pane. It gives you critical feedback for knowing
which devices are connected and what state they are in. And the other
tools—including project archives with submission to the App Store, the
documentation interface, and the screenshot utility—just add to its power.
- Xcode
4’s massive update has more power and capabilities than this brief introduction
can cover. Other features are discussed in Chapter 4, “Designing Interfaces,”
which provides a more detailed overview of Interface Builder.
©
Copyright Pearson Education. All rights reserved.