- •Contents at a Glance
- •About the Authors
- •About the Technical Reviewer
- •Acknowledgments
- •Preface
- •What This Book Is
- •What You Need
- •Developer Options
- •What You Need to Know
- •What’s Different About Coding for iOS?
- •Only One Active Application
- •Only One Window
- •Limited Access
- •Limited Response Time
- •Limited Screen Size
- •Limited System Resources
- •No Garbage Collection, but…
- •Some New Stuff
- •A Different Approach
- •What’s in This Book
- •What’s New in This Update?
- •Are You Ready?
- •Setting Up Your Project in Xcode
- •The Xcode Workspace Window
- •The Toolbar
- •The Navigator View
- •The Jump Bar
- •The Utility Pane
- •Interface Builder
- •New Compiler and Debugger
- •A Closer Look at Our Project
- •Introducing Xcode’s Interface Builder
- •What’s in the Nib File?
- •The Library
- •Adding a Label to the View
- •Changing Attributes
- •Some iPhone Polish—Finishing Touches
- •Bring It on Home
- •The Model-View-Controller Paradigm
- •Creating Our Project
- •Looking at the View Controller
- •Understanding Outlets and Actions
- •Outlets
- •Actions
- •Cleaning Up the View Controller
- •Designing the User Interface
- •Adding the Buttons and Action Method
- •Adding the Label and Outlet
- •Writing the Action Method
- •Trying It Out
- •Looking at the Application Delegate
- •Bring It on Home
- •A Screen Full of Controls
- •Active, Static, and Passive Controls
- •Creating the Application
- •Implementing the Image View and Text Fields
- •Adding the Image View
- •Resizing the Image View
- •Setting View Attributes
- •The Mode Attribute
- •Interaction Checkboxes
- •The Alpha Value
- •Background
- •Drawing Checkboxes
- •Stretching
- •Adding the Text Fields
- •Text Field Inspector Settings
- •Setting the Attributes for the Second Text Field
- •Creating and Connecting Outlets
- •Closing the Keyboard
- •Closing the Keyboard When Done Is Tapped
- •Touching the Background to Close the Keyboard
- •Adding the Slider and Label
- •Creating and Connecting the Actions and Outlets
- •Implementing the Action Method
- •Adding Two Labeled Switches
- •Connecting and Creating Outlets and Actions
- •Implementing the Switch Actions
- •Adding the Button
- •Connecting and Creating the Button Outlets and Actions
- •Implementing the Segmented Control Action
- •Implementing the Action Sheet and Alert
- •Conforming to the Action Sheet Delegate Method
- •Showing the Action Sheet
- •Spiffing Up the Button
- •Using the viewDidLoad Method
- •Control States
- •Stretchable Images
- •Crossing the Finish Line
- •The Mechanics of Autorotation
- •Points, Pixels, and the Retina Display
- •Autorotation Approaches
- •Handling Rotation Using Autosize Attributes
- •Configuring Supported Orientations
- •Specifying Rotation Support
- •Designing an Interface with Autosize Attributes
- •Using the Size Inspector’s Autosize Attributes
- •Setting the Buttons’ Autosize Attributes
- •Restructuring a View When Rotated
- •Creating and Connecting Outlets
- •Moving the Buttons on Rotation
- •Swapping Views
- •Designing the Two Views
- •Implementing the Swap
- •Changing Outlet Collections
- •Rotating Out of Here
- •Common Types of Multiview Apps
- •The Architecture of a Multiview Application
- •The Root Controller
- •Anatomy of a Content View
- •Building View Switcher
- •Creating Our View Controller and Nib Files
- •Modifying the App Delegate
- •Modifying BIDSwitchViewController.h
- •Adding a View Controller
- •Building a View with a Toolbar
- •Writing the Root View Controller
- •Implementing the Content Views
- •Animating the Transition
- •Switching Off
- •The Pickers Application
- •Delegates and Data Sources
- •Setting Up the Tab Bar Framework
- •Creating the Files
- •Adding the Root View Controller
- •Creating TabBarController.xib
- •The Initial Test Run
- •Implementing the Date Picker
- •Implementing the Single-Component Picker
- •Declaring Outlets and Actions
- •Building the View
- •Implementing the Controller As a Data Source and Delegate
- •Implementing a Multicomponent Picker
- •Declaring Outlets and Actions
- •Building the View
- •Implementing the Controller
- •Implementing Dependent Components
- •Creating a Simple Game with a Custom Picker
- •Writing the Controller Header File
- •Building the View
- •Adding Image Resources
- •Implementing the Controller
- •The spin Method
- •The viewDidLoad Method
- •Final Details
- •Linking in the Audio Toolbox Framework
- •Final Spin
- •Table View Basics
- •Table Views and Table View Cells
- •Grouped and Plain Tables
- •Implementing a Simple Table
- •Designing the View
- •Writing the Controller
- •Adding an Image
- •Using Table View Cell Styles
- •Setting the Indent Level
- •Handling Row Selection
- •Changing the Font Size and Row Height
- •Customizing Table View Cells
- •Adding Subviews to the Table View Cell
- •Creating a UITableViewCell Subclass
- •Adding New Cells
- •Implementing the Controller’s Code
- •Loading a UITableViewCell from a Nib
- •Designing the Table View Cell in Interface Builder
- •Using the New Table View Cell
- •Grouped and Indexed Sections
- •Building the View
- •Importing the Data
- •Implementing the Controller
- •Adding an Index
- •Implementing a Search Bar
- •Rethinking the Design
- •A Deep Mutable Copy
- •Updating the Controller Header File
- •Modifying the View
- •Modifying the Controller Implementation
- •Copying Data from allNames
- •Implementing the Search
- •Changes to viewDidLoad
- •Changes to Data Source Methods
- •Adding a Table View Delegate Method
- •Adding Search Bar Delegate Methods
- •Adding a Magnifying Glass to the Index
- •Adding the Special Value to the Keys Array
- •Suppressing the Section Header
- •Telling the Table View What to Do
- •Putting It All on the Table
- •Navigation Controller Basics
- •Stacky Goodness
- •A Stack of Controllers
- •Nav, a Hierarchical Application in Six Parts
- •Meet the Subcontrollers
- •The Disclosure Button View
- •The Checklist View
- •The Rows Control View
- •The Movable Rows View
- •The Deletable Rows View
- •The Editable Detail View
- •The Nav Application’s Skeleton
- •Creating the Top-Level View Controller
- •Setting Up the Navigation Controller
- •Adding the Images to the Project
- •First Subcontroller: The Disclosure Button View
- •Creating the Detail View
- •Modifying the Disclosure Button Controller
- •Adding a Disclosure Button Controller Instance
- •Second Subcontroller: The Checklist
- •Creating the Checklist View
- •Adding a Checklist Controller Instance
- •Third Subcontroller: Controls on Table Rows
- •Creating the Row Controls View
- •Adding a Rows Control Controller Instance
- •Fourth Subcontroller: Movable Rows
- •Creating the Movable Row View
- •Adding a Move Me Controller Instance
- •Fifth Subcontroller: Deletable Rows
- •Creating the Deletable Rows View
- •Adding a Delete Me Controller Instance
- •Sixth Subcontroller: An Editable Detail Pane
- •Creating the Data Model Object
- •Creating the Detail View List Controller
- •Creating the Detail View Controller
- •Adding an Editable Detail View Controller Instance
- •But There’s One More Thing. . .
- •Breaking the Tape
- •Creating a Simple Storyboard
- •Dynamic Prototype Cells
- •Dynamic Table Content, Storyboard-Style
- •Editing Prototype Cells
- •Good Old Table View Data Source
- •Will It Load?
- •Static Cells
- •Going Static
- •So Long, Good Old Table View Data Source
- •You Say Segue, I Say Segue
- •Creating Segue Navigator
- •Filling the Blank Slate
- •First Transition
- •A Slightly More Useful Task List
- •Viewing Task Details
- •Make More Segues, Please
- •Passing a Task from the List
- •Handling Task Details
- •Passing Back Details
- •Making the List Receive the Details
- •If Only We Could End with a Smooth Transition
- •Split Views and Popovers
- •Creating a SplitView Project
- •The Storyboard Defines the Structure
- •The Code Defines the Functionality
- •The App Delegate
- •The Master View Controller
- •The Detail View Controller
- •Here Come the Presidents
- •Creating Your Own Popover
- •iPad Wrap-Up
- •Getting to Know Your Settings Bundle
- •The AppSettings Application
- •Creating the Project
- •Working with the Settings Bundle
- •Adding a Settings Bundle to Our Project
- •Setting Up the Property List
- •Adding a Text Field Setting
- •Adding an Application Icon
- •Adding a Secure Text Field Setting
- •Adding a Multivalue Field
- •Adding a Toggle Switch Setting
- •Adding the Slider Setting
- •Adding Icons to the Settings Bundle
- •Adding a Child Settings View
- •Reading Settings in Our Application
- •Retrieving User Settings
- •Creating the Main View
- •Updating the Main View Controller
- •Registering Default Values
- •Changing Defaults from Our Application
- •Keeping It Real
- •Beam Me Up, Scotty
- •Your Application’s Sandbox
- •Getting the Documents Directory
- •Getting the tmp Directory
- •File-Saving Strategies
- •Single-File Persistence
- •Multiple-File Persistence
- •Using Property Lists
- •Property List Serialization
- •The First Version of the Persistence Application
- •Creating the Persistence Project
- •Designing the Persistence Application View
- •Editing the Persistence Classes
- •Archiving Model Objects
- •Conforming to NSCoding
- •Implementing NSCopying
- •Archiving and Unarchiving Data Objects
- •The Archiving Application
- •Implementing the BIDFourLines Class
- •Implementing the BIDViewController Class
- •Using iOS’s Embedded SQLite3
- •Creating or Opening the Database
- •Using Bind Variables
- •The SQLite3 Application
- •Linking to the SQLite3 Library
- •Modifying the Persistence View Controller
- •Using Core Data
- •Entities and Managed Objects
- •Key-Value Coding
- •Putting It All in Context
- •Creating New Managed Objects
- •Retrieving Managed Objects
- •The Core Data Application
- •Designing the Data Model
- •Creating the Persistence View and Controller
- •Persistence Rewarded
- •Managing Document Storage with UIDocument
- •Building TinyPix
- •Creating BIDTinyPixDocument
- •Code Master
- •Initial Storyboarding
- •Creating BIDTinyPixView
- •Storyboard Detailing
- •Adding iCloud Support
- •Creating a Provisioning Profile
- •Enabling iCloud Entitlements
- •How to Query
- •Save Where?
- •Storing Preferences on iCloud
- •What We Didn’t Cover
- •Grand Central Dispatch
- •Introducing SlowWorker
- •Threading Basics
- •Units of Work
- •GCD: Low-Level Queueing
- •Becoming a Blockhead
- •Improving SlowWorker
- •Don’t Forget That Main Thread
- •Giving Some Feedback
- •Concurrent Blocks
- •Background Processing
- •Application Life Cycle
- •State-Change Notifications
- •Creating State Lab
- •Exploring Execution States
- •Making Use of Execution State Changes
- •Handling the Inactive State
- •Handling the Background State
- •Removing Resources When Entering the Background
- •Saving State When Entering the Background
- •A Brief Journey to Yesteryear
- •Back to the Background
- •Requesting More Backgrounding Time
- •Grand Central Dispatch, Over and Out
- •Two Views of a Graphical World
- •The Quartz 2D Approach to Drawing
- •Quartz 2D’s Graphics Contexts
- •The Coordinate System
- •Specifying Colors
- •A Bit of Color Theory for Your iOS Device’s Display
- •Other Color Models
- •Color Convenience Methods
- •Drawing Images in Context
- •Drawing Shapes: Polygons, Lines, and Curves
- •The QuartzFun Application
- •Setting Up the QuartzFun Application
- •Creating a Random Color
- •Defining Application Constants
- •Implementing the QuartzFunView Skeleton
- •Creating and Connecting Outlets and Actions
- •Implementing the Action Methods
- •Adding Quartz 2D Drawing Code
- •Drawing the Line
- •Drawing the Rectangle and Ellipse
- •Drawing the Image
- •Optimizing the QuartzFun Application
- •The GLFun Application
- •Setting Up the GLFun Application
- •Creating BIDGLFunView
- •Updating BIDViewController
- •Updating the Nib
- •Finishing GLFun
- •Drawing to a Close
- •Multitouch Terminology
- •The Responder Chain
- •Responding to Events
- •Forwarding an Event: Keeping the Responder Chain Alive
- •The Multitouch Architecture
- •The Four Touch Notification Methods
- •The TouchExplorer Application
- •The Swipes Application
- •Automatic Gesture Recognition
- •Implementing Multiple Swipes
- •Detecting Multiple Taps
- •Detecting Pinches
- •Defining Custom Gestures
- •The CheckPlease Application
- •The CheckPlease Touch Methods
- •Garçon? Check, Please!
- •The Location Manager
- •Setting the Desired Accuracy
- •Setting the Distance Filter
- •Starting the Location Manager
- •Using the Location Manager Wisely
- •The Location Manager Delegate
- •Getting Location Updates
- •Getting Latitude and Longitude Using CLLocation
- •Error Notifications
- •Trying Out Core Location
- •Updating Location Manager
- •Determining Distance Traveled
- •Wherever You Go, There You Are
- •Accelerometer Physics
- •Don’t Forget Rotation
- •Core Motion and the Motion Manager
- •Event-Based Motion
- •Proactive Motion Access
- •Accelerometer Results
- •Detecting Shakes
- •Baked-In Shaking
- •Shake and Break
- •Accelerometer As Directional Controller
- •Rolling Marbles
- •Writing the Ball View
- •Calculating Ball Movement
- •Rolling On
- •Using the Image Picker and UIImagePickerController
- •Implementing the Image Picker Controller Delegate
- •Road Testing the Camera and Library
- •Designing the Interface
- •Implementing the Camera View Controller
- •It’s a Snap!
- •Localization Architecture
- •Strings Files
- •What’s in a Strings File?
- •The Localized String Macro
- •Real-World iOS: Localizing Your Application
- •Setting Up LocalizeMe
- •Trying Out LocalizeMe
- •Localizing the Nib
- •Localizing an Image
- •Generating and Localizing a Strings File
- •Localizing the App Display Name
- •Auf Wiedersehen
- •Apple’s Documentation
- •Mailing Lists
- •Discussion Forums
- •Web Sites
- •Blogs
- •Conferences
- •Follow the Authors
- •Farewell
- •Index
352 CHAPTER 9: Navigation Controllers and Table Views
UITextField *nextField = nil;
for (UIView *oneView in nextCell.contentView.subviews) { if ([oneView isMemberOfClass:[UITextField class]])
nextField = (UITextField *)oneView;
}
Finally, we can tell that new text field to become the first responder.
[nextField becomeFirstResponder];
Now, compile and run. This time, when you drill down to the detail view, tapping the Return button will take you to the next field in the table, which will make entering data much easier for your users.
Breaking the Tape
This chapter was a marathon, and if you’re still standing, you should feel pretty darn good about yourself. Dwelling on these mystical table view and navigation controller objects is important because they are the backbone of a great many iOS applications, and their complexity can definitely get you into trouble if you don’t truly understand them.
As you start building your own tables, check back to this chapter and the previous one, and don’t be afraid of Apple’s documentation, either. Table views are extraordinarily complex, and we could never cover every conceivable permutation, but you should now have a very good set of table view building blocks you can use as you design and build your own applications. As always, feel free to reuse this code in your own applications. It’s a gift from us to you. Enjoy!
In the next chapter, we’re going to introduce you to Storyboards, one of the biggest new features iOS 5 brings to developers. That’s right, the Storyboards concept isn’t really an end-user feature, but rather a set of enhancements to Xcode and new APIs in UIKit, which allow developers to design the structure of a complex navigation-based application in a whole new way. Storyboards will make your job much easier and even more fun!
www.it-ebooks.info
Chapter10
Storyboards
Over the course of the past several chapters, you’ve become intimately familiar with nib files, the UITableView class, and navigating between views using UINavigationViewController. Together, these building blocks make up a robust, flexible tool kit for building mobile apps, as evidenced by the hundreds of thousands of iPhone and iPad applications that have been created in the past few years.
However, there’s always room for improvement. As more and more people have been introduced to these tools, some of their shortcomings have started to feel like a burden. As you’ve been learning, you may have wondered about some of these issues yourself:
The delegate/dataSource pattern for specifying UITableView content is great for creating dynamic tables, but if you know in advance precisely what your table will contain, isn’t it all a bit wordy? What if you could specify table contents in a more declarative manner, skipping all the call and response that the current system entails?
The use of nib files for storing freeze-dried object graphs is great, as far as it goes. But if your app has more than one view controller, as almost all apps do, switching between them always requires a certain amount of manual labor in the form of redundant, boilerplate code. What if this could be streamlined?
In a complex application with many view controllers, it can be hard to see the big picture. Communications and transitions between controllers are codified within every controller class. Not only does this make it hard to read an app’s source code, requiring you to study delegate and action methods in each controller to see how it connects to other controllers, but it also makes the app’s code more fragile. What if you had a way to describe interactions between view controllers at a level outside the controllers themselves, letting you see the entire flow of data and interactions in one place?
If you’ve been concerned about any of these issues, you’re in luck! As it turns out, Apple has been concerned about them, too. It has included with the iOS 5 SDK a new system called Storyboards that aims to solve each of these problems.
D.Mark et al., Beginning iOS 5 Development
©Dave Mark, Jack Nutting, Jeff LaMarche 2011
www.it-ebooks.info
354 |
CHAPTER 10: Storyboards |
Storyboards build on the familiar nib concept, and are edited in the same way, using Xcode’s Interface Builder. But unlike nibs, storyboards also allow you to work with multiple views, each attached to its own view controller, in a single visual workspace. You can configure how transitions between view controllers should occur, and you can also configure a table view with a fixed set of predefined cells. In this chapter, we’ll explore some of these new capabilities so you can get a feel for storyboards, see how they differ from nib files, and figure out where to work storyboards into your own apps.
NOTE: As you’ll see, storyboards are awesome. It’s important to know, though, that at the moment at least, storyboards will run only on devices sporting iOS 5 and above. That will be less
of an issue as more and more people move to iOS 5 over time.
Creating a Simple Storyboard
Let’s start off with a simple project to demonstrate some of the basic characteristics of storyboards. In Xcode, select File New New Project… to create a new project. Select
Single View Application from the iOS Application group, and click Next. Name the project Simple Storyboard, click to enable the Use Storyboard checkbox, and click Next again. Finally, select the directory where you want to save your project and click Create.
Once the project is created, look at the project navigator. You’ll see some familiar sights, such as the BIDAppDelegate and BIDViewController class files. You’ll also notice that there’s no BIDViewController.xib, but there is a MainStoryboard.storyboard file. The storyboard file isn’t named after the view controller because, unlike nibs, a storyboard is designed to be able to easily represent content for several view controllers.
Select MainStoryboard.storyboard, and you’ll see that Xcode switches into the familiar Interface Builder display, as shown in Figure 10-1. Some subtle differences exist between the nib editing interface we’ve used up to this point and the storyboard editing interface. For example, the storyboard Interface Builder editor doesn’t contain an icon mode when working with a storyboard. Instead, clicking the disclosure triangle to the right of the bottom of the dock makes the entire dock collapse and disappear.
www.it-ebooks.info
CHAPTER 10: Storyboards |
355 |
Figure 10-1. A view controller, as seen in a storyboard
Another example involves the first responder and view controller icons. If you select
View Controller in the dock, the First Responder and View Controller icons will appear below the view controller, in addition to appearing in the dock (see Figure 10-2). In a storyboard, each view and its corresponding view controller always appear together in this way, and together they are referred to as a scene.
www.it-ebooks.info
356 |
CHAPTER 10: Storyboards |
Figure 10-2. When you select View Controller, the First Responder and View Controller icons appear below the view controller.
You’ll also see that the view shown in the editing area has a big arrow pointing to it. This will come in handy later in this chapter when we create storyboards containing multiple views. The arrow points out which view controller is the initial view controller that should be loaded and displayed when the app loads this storyboard. When you actually have multiple views in your storyboard, you simply drag the arrow around to point to the correct initial view controller. Right now, we have only one view. If you try dragging the arrow around, you’ll see that it always pops back to where it started as soon as you release the mouse button.
The other big change to the editing area is that you can zoom in and out with a set of controls at the lower right of the editing pane. This is handy when dealing with a lot of view controllers in a storyboard, since it allows you to see several view controllers and the connections between them all at once. Note that when you’re zoomed out, Interface Builder won’t let you drag any objects from the object library into your views. You also can’t select any of the objects inside your views when you’re zoomed out. So, overall, this isn’t really a useful mode for editing your views, but it is a good way to get a sense of the overall picture.
www.it-ebooks.info
CHAPTER 10: Storyboards |
357 |
Now, let’s add a label to our view. Make sure you’re zoomed all the way in, and drag a Label from the object library to the center of the view. Double-click the label to select its text, and change the text to Simple. Run your application, and you’ll see your app launch and display the label you just created.
You’ve seen some template-generated apps before, but with storyboards, things are a little different. Let’s take a look at the rest of our project to see what’s happening with the storyboard-based app behind the scenes.
In the project navigator, select BIDViewController.m, and take a look through the code. Except for the autorotation method, all the methods in this file send a message to the superclass and then return. Certainly, there’s no mention of our storyboard here.
Move on to BIDAppDelegate.m. You’ll see a series of empty methods. Direct your attention to application:didFinishLaunchingWithArguments:, which looks quite a bit different from how the same method has been implemented in our other apps. In the apps we’ve created up to this point, this method has contained code to create a UIWindow, perhaps open a nib file, and more. This one, however, is pretty empty! So, how does our app know that it’s supposed to load our storyboard, and how does its initial view get put into a window? Bottom line: the key to this question lies in the target settings.
Go to the project navigator and select the topmost Simple Storyboard item, which represents the project itself. Make sure the Simple Storyboard target is also selected, along with the Summary tab at the top, and look for the iPhone / iPod Deployment Info section, where you’ll see that MainStoryboard is configured as the Main Storyboard (see Figure 10-3).
As it turns out, that’s all the configuration required to make your app automatically create a window, load the storyboard and its initial view, create the initial view controller specified in the storyboard, and hook it all up. That means, among other things, that the application delegate gets to be a little simpler, since the creation of the window and the initial view are all taken care of for you. All of the wiring is done behind the scenes, but if you enable storyboarding in a project, you get this simplification for free.
www.it-ebooks.info