- •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
372 |
CHAPTER 10: Storyboards |
First Transition
It’s time to create our first segue. Start by dragging a View Controller from the object library into the layout area, dropping it somewhere to the right of the other views. We’re not going to display any special content here, because we really just want to jump into a segue. That being said, you need to have some way of visually confirming that the correct view is being shown, so drag a UILabel from the object library into the new view, change its text to Single View, and center the label vertically and horizontally in the view.
Now comes the segue-creation magic. Control-drag from the Single view cell in the middle table view controller to the new view you just added. You’ll see the Storyboard Segues popup again, this time without the rootViewController relationship you saw previously. It contains only the three kinds of segues that Interface Builder supports: Push, Modal, and Custom. Choose Push, because here we want to implement the standard navigation controller model involving pushing controllers onto a stack. Once you do this, you’ll see a new connection arrow appear, pointing to our new controller from the root view controller. You’ll also see that the Single view row in the root table view has acquired a disclosure arrow on the right side, to let the user know that there’s something more to be discovered by tapping that cell.
Run your app again, and you’ll see that the top cell now contains the disclosure arrow you just saw, and tapping the row takes you to the new view that you just set up. You’ll see the label you added, the title at the top of screen, and the back button, which is labeled Seg Nav (remember that we configured that a page or two ago). Press the back button to make sure it takes you back to the root view.
So, now we have a fair amount of view navigation going on, without having written any code at all. This elimination of boring glue code is one of the biggest wins involved when using segues. But, of course, you can’t eliminate all your code. Let’s see what it takes to make a GUI that displays a list of items in a normal, dynamically sized table view, and lets you select one of those items to drill down into more detail. Note that this will require a bit of code so the list controller can pass the selected item off to the detail controller. With segues, that sort of thing can be handled a bit more simply than before, as you’ll soon see.
A Slightly More Useful Task List
We’re going to make a slightly more capable version of the task list that we created in the Simple Storyboard example earlier. In this version, you’ll see a list of tasks, and also be able to tap on one to edit it. Fortunately, we can build on what we created earlier to make this go pretty easily.
Open the Simple Storyboard project you created earlier in the chapter, and drag the
BIDTaskListController.h and BIDTaskListController.m files from that project onto the Seg Nav folder in the Seg Nav project. When Xcode asks, make sure you turn on the checkbox telling Xcode to copy the files into the project. This will copy the files from the
www.it-ebooks.info
CHAPTER 10: Storyboards |
373 |
Simple Storyboard project folder on your hard drive into the Seq Nav folder on your hard drive and add the two files to the Seq Nav project.
Next, select the Seg Nav folder in the project navigator, and choose File New New File… to make a new file. Select the Cocoa Touch section on the left, select
UIViewController subclass, and click Next. Name this class BIDTaskDetailController, and choose UIViewController as its superclass. Do not have Xcode create the accompanying nib file. Create this class, but don’t edit it in any way just yet. We’ll get back to it soon enough, after setting up the GUI.
Switch over to MainStoryboard.storyboard. It’s time to create the next scene in our storyboard, which will be the task list display. Drag a UITableViewController from the object library to the layout area, placing it to the right of the other controllers. Use the identity inspector to change the new controller’s class to BIDTaskListController.
In the dock, select the table view associated with the new controller. Now, open the attributes inspector and take a look at the Content popup menu. Since the table view we just added will display a dynamic list of items, we’re going to leave it set to Dynamic Prototypes instead of switching to Static Cells.
We’ll use the same two prototype cells we described earlier in the “Dynamic Prototype Cells” section. Either flip back there to see how those were configured or open Simple Storyboard and copy both cells, pasting them into your new table. To recap, the critical configuration points are making sure that each cell has a label, each label has its tag set to 1, and the cells have plainCell and attentionCell set as their identifiers.
If you want to copy the two cells from Simple Storyboard instead of re-creating them, switch over to the Simple Storyboard project and find the two table view cells in the
Task List Controller Scene. They should be labeled plainCell and attentionCell. Close the disclosure triangles, and select both cells (that way, you get the labels, too). Copy, then switch over to the Seg Nav project, select the new table view, and paste. Your cells and labels should appear in your new controller. Delete the original cell, leaving you with two prototype cells instead of three.
Viewing Task Details
Now, we’re going to add another scene to manage the detail display that’s shown when the user selects a row in the task list. Drag a View Controller (not a Table View Controller) from the object library to the layout area, placing it to the right of the previous scene. Use the identity inspector to change the controller’s class to
BIDTaskDetailController.
This scene is all about editing the details of a chosen task, which in our simple case, means just editing a string. To accomplish this, we’ll use a UITextView, the full-featured multiline text editor employed throughout iOS. Drag one of those from the object library into the new scene. You’ll see that it snaps into place, filling the entire space. Since we want to let users edit this text, filling the screen isn’t what we want. We’ll be better off with a smaller text view that just fills the space that the on-screen keyboard doesn’t cover. Grab the resize handle in the center of the bottom edge, and drag it upward until
www.it-ebooks.info
374 |
CHAPTER 10: Storyboards |
the text view is just 200 pixels tall. A coordinate display appears at the top of the view when you start dragging, to make this easier.
Next, we need to add an outlet to the controller so that it can find this text view to set and retrieve the string it contains. We can create and connect that outlet in one step using Interface Builder’s drag-to-code feature, so let’s do that. First bring up the assistant editor. With the BIDTaskDetailController or any part of its view selected in the layout editor, the assistant editor should show the controller’s header file, BIDTaskDetailController.h. If not, then the assistant editor probably isn’t in automatic mode. You can fix that using the jump bar above the assistant editor, clicking the icon just to the right of the arrows, and selecting Automatic.
Now, select the text view, and control-drag from it to the code, dropping it anywhere between the @interface and @end lines. In the popup that appears, make sure the Connection type is set to Outlet, and name it textView. Also make sure Storage is set to Weak, and then click Connect. This creates a new outlet in the BIDTaskDetailController.h, and synthesizes the getter and setter in BIDTaskDetailController.m.
Make More Segues, Please
With the basic GUIs for our new scenes set up, it’s time to connect them using segues. Start by heading back to our root table view (the one with the Simple View and Submenu cells). Select the Sub-menu cell, and control-drag from it to the task list controller. It is probably easiest to do this in the dock. Note that this control-drag will be skipping over the Single View scene. In the popup that appears, select Push so that the segue will push the task list scene onto the stack when Sub-menu is tapped.
Now, select the first prototype cell in the task list controller scene (it’s called Table View Cell – plainCell in the dock, and you might need to open a disclosure triangle to see it), and control-drag from there to the Task Detail Controller, again selecting Push. Do the same for the second prototype cell (it’s called Table View Cell – attentionCell in the dock), so that both are connected to the Task Detail Controller. This will show up as two arrows pointing from the task list to the task detail. Each arrow represents a segue, and each comes from a specific prototype cell. When you run the app later, all the cells that are created for the task list are duplicated from one of these prototypes, so each of them will have a segue that enables them to create and activate a task detail controller.
At this point, our GUI configuration is complete. All we need to do is implement a few methods to pass the selected task from the list view to the detail view, then back the other way after the user has had a chance to view and edit the task.
Passing a Task from the List
Select BIDTaskListController.m, and add this method to the class at the end of the file, just above the @end:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { UIViewController *destination = segue.destinationViewController;
www.it-ebooks.info
CHAPTER 10: Storyboards |
375 |
if ([destination respondsToSelector:@selector(setDelegate:)]) { [destination setValue:self forKey:@"delegate"];
}
if ([destination respondsToSelector:@selector(setSelection:)]) { // prepare selection info
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; id object = [self.tasks objectAtIndex:indexPath.row];
NSDictionary *selection = [NSDictionary dictionaryWithObjectsAndKeys: indexPath, @"indexPath",
object, @"object", nil];
[destination setValue:selection forKey:@"selection"];
}
}
This new prepareForSegue:sender: method is called in our controller whenever our controller’s view is about to be replaced by another controller’s view as a result of a segue being activated. In our case, this means that when any of the cells in our table view is selected, the cell will activate its associated segue, and this method will be called in our controller. This gives us a chance to prepare data to pass along to the next controller. In the past, we did this sort of thing in a table view delegate method that was called when a row was selected, but this new way is a bit more flexible. We could, for instance, replace our table view cells with buttons, and as long as those buttons use segues to launch other view controllers, this method will be called in the same way as it is now.
We have some new things here, so let’s walk through the prepareForSegue:sender: method together. Through the segue parameter that we’re given, we can access the destinationViewController (the one that’s going to be displayed in a moment) and the sourceViewController (the one that’s about to be removed from the display). In this case, we’ll use the destinationViewController property to configure the detail view controller, so we put it into a local variable for easy access:
UIViewController *destination = segue.destinationViewController;
Next, we configure the destination’s delegate, if it has one, to point back at us. That will let the destination send us back data when it’s finished. Right now, our detail display doesn’t have a delegate property, but it will later.
if ([destination respondsToSelector:@selector(setDelegate:)]) { [destination setValue:self forKey:@"delegate"];
}
KEY-VALUE CODING
Instead of calling a setDelegate: method, we’re using something called key-value coding (KVC), which allows us to use getters and setters on any object indirectly, using strings instead of method names. KVC is a core feature of the Cocoa Touch frameworks, and its main methods—setValue:forKey: and valueForKey:—are built into NSObject, so they’re available everywhere. We’re not covering this topic in detail in this book, but are using it briefly here.
www.it-ebooks.info