- •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
698 |
CHAPTER 21: Application Localization |
Figure 21–8. The application is partially translated into French now.
Localizing an Image
We could change the flag image directly in the nib by just selecting a different image for the image view in the French localized nib file. Instead of doing that, we’ll actually localize the flag image itself.
When an image or other resource used by a nib is localized, the nib will automatically show the correct version for the language (though not for the dialect, at the time of this writing). If we localize the flag.png file itself with a French version, the nib will automatically show the correct flag when appropriate.
First, quit the simulator and make sure your application is stopped. Back in Xcode, single-click flag.png in the project navigator. Next, bring up the file inspector, and locate the Localization section, which you’ll see is currently empty. Make sure flag.png is still selected, and then press the + button at the bottom of the Localization section. Xcode will add an English localization for the file and move flag.png into the en.lproj folder (check the Finder to see this for yourself).
www.it-ebooks.info
CHAPTER 21: Application Localization |
699 |
NOTE: In the current version of Xcode 4.2, there seems to be a slight bug in the GUI that shows up here. With flag.png selected, clicking the + button as we just described causes the file to be deselected, which makes the inspector suddenly pop into a no selection state. But don’t worry; it
has done its work properly anyway. Just select flag.png in the project navigator again and
continue.
You’ll see that where flag.png is shown in the project navigator, there’s still no disclosure triangle to indicate that it’s a localized resource. That’s because we still have just one version of it, in en.lproj, just as BIDViewController.xib started out.
Make sure flag.png is still selected, and use the Localization section of the file inspector to add a new localization. This time when the popup list appears, you’ll see both English and French at the top of the list, since Xcode knows those are already represented in the project. Select French, and you’ll see that flag.png immediately acquires a disclosure icon. Expand that, and you’ll see two copies of the flag: one labeled English and one labeled French.
Switch back to the Finder and your project’s directory, and you’ll see this situation mirrored in the file system, with en.lproj and fr.lproj each containing a flag.png file. The one in fr.lproj is a copy of the original, which is obviously not the correct image. Since Xcode doesn’t let you edit image files, the easiest way to get the correct image into the localization project is to just copy that image into the project using the Finder.
Go to the 21 - LocalizeMe folder, open the Images folder, open the French folder, and use the flag.png file in that folder to replace the flag.png you’ll find in LocalizeMe/fr.lproj.
That’s it. You’re finished. Back in Xcode, click the image file flag.png (French) in the project navigator. You should see the French flag.
Now, try running the app again. We hope you’ll see something akin to the image shown in Figure 21–9. If not, do not despair. Chances are the US version of the flag image is being cached, either by the simulator or by the device, if you are running the app that way. We’ll go over a couple approaches you can try to get the correct image.
www.it-ebooks.info
700 |
CHAPTER 21: Application Localization |
Figure 21–9. The flag image and application nib are both localized to French now.
If you are running in the simulator, first quit the app (but not the simulator). Click over to Xcode and stop the application. Return to the simulator and select iOS Simulator Reset Contents and Settings to reset the simulator, and then quit the simulator. Return to Xcode and select Product Clean to force a complete rebuild. Now, run the app again. Once you rerun the app, you’ll need to reset the region and language to get the French flag to appear. If this still does not work, try doing the simulator reset, quit the simulator, do a Product Clean, quit Xcode, and then start the whole thing again.
If you’re running on the device, your iPhone has probably cached the American flag from the last time you ran the application. You can remove the old application from your iPhone using the Organizer window in Xcode. Select Window Organizer to bring up the Organizer window. Under the Devices tab, you’ll see a column on the left showing all the iOS devices that Xcode knows about. The currently connected device has a green dot next to its name. Select the Applications item belonging to your devices, and you’ll see a list of all the applications you’ve compiled and installed on your own. Find LocalizeMe in the list, select it, and click the minus (–) button to remove the old version of that application and the caches associated with it. Now, select Project Clean. When that’s complete, build and run the application again. Once the application launches, you’ll need to reset the region, and then the language. The French flag should now come up in addition to the French words down the left side (see Figure 21–9).
www.it-ebooks.info
CHAPTER 21: Application Localization |
701 |
Generating and Localizing a Strings File
In Figure 21–9, notice that the words on the right side of the view are still in English. In order to translate those, we need to generate our base language strings file and then localize that. To accomplish this, we’ll need to leave the comfy confines of Xcode for a few minutes.
Launch Terminal.app, which is in /Applications/Utilities/. When the terminal window opens, type cd followed by a space. Don’t press return.
Now, go to the Finder, and drag the project folder 21 - LocalizeMe to the terminal window. As soon as you drop the folder onto the terminal window, the path to the project folder should appear on the command line. Now, press return. The cd command is Unix-speak for “change directory,” so what you’ve just done is steer your terminal session from its default directory over to your project directory.
Our next step is to run the program genstrings and tell it to find all the occurrences of NSLocalizedString in your .m files in the Classes folder. To do this, type the following command, and then press return:
genstrings ./LocalizeMe/*.m
When the command is finished executing (it just takes a second on a project this small), you’ll be returned to the command line. In the Finder, look in the project folder for a new file called Localizable.strings. Drag that to the LocalizeMe folder in Xcode’s project navigator, but when it prompts you, don’t click the Add button just yet. First uncheck the box that says Copy items into destination group’s folder (if needed), because the file is already in your project folder. Click Finish to import the file.
CAUTION: You can rerun genstrings at any time to re-create your base language file, but once you have localized your strings file into another language, it’s important that you don’t change the text used in any of the NSLocalizedString() macros. That base-language version of the string is used as a key to retrieve the translations, so if you change them, the translated version will no longer be found, and you will need to either update the localized strings file or have it
retranslated.
Once the file is imported, single-click Localizable.strings, and take a look at it. It contains five entries, because we use NSLocalizableString five times with five distinct values. The values that we passed in as the second argument have become the comments for each of the strings.
The strings were generated in alphabetical order. In this case, since we’re dealing with numbers, alphabetical order is not the most intuitive way to present them, but in most cases, having them in alphabetical order will be helpful.
/* The number 5 */ "Five" = "Five";
www.it-ebooks.info
702CHAPTER 21: Application Localization
/* The number 4 */ "Four" = "Four";
/* The number 1 */ "One" = "One";
/* The number 3 */ "Three" = "Three";
/* The number 2 */ "Two" = "Two";
Let’s localize this sucker.
Make sure Localizable.strings is selected, and then repeat the same steps we’ve performed for the other localizations:
Open the file inspector if it’s not already visible.
In the Localizations section, click the + button once to create an English localization. This will likely unselect the file, but it will create the English localization.
Reselect Localizable.strings. Then click the + button once again to make a French localization.
Back in the project navigator, select the French localization of the file. In the editor, make the following changes:
/* The number 5 */ "Five" = "Cinq";
/* The number 4 */ "Four" = "Quatre";
/* The number 1 */ "One" = "Un";
/* The number 3 */ "Three" = "Trois";
/* The number 2 */ "Two" = "Deux";
In real life (unless you’re multilingual), you would ordinarily send this file out to a translation service to translate the values to the right of the equal signs. In this simple example, armed with knowledge that came from years of watching Sesame Street, we can do the translation ourselves.
Now save, compile, and run the app. You should see the relevant numbers translated into French.
www.it-ebooks.info