Iphone App Programming Guide
Iphone App Programming Guide
General
2011-10-12
Apple Inc. 2011 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apples copyright notice. The Apple logo is a trademark of Apple Inc. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 App Store is a service mark of Apple Inc. Apple, the Apple logo, AirPlay, Bonjour, Cocoa, Instruments, iPhone, iPod, iPod touch, iTunes, Keychain, Mac, Mac OS, Macintosh, Numbers, Objective-C, Sand, and Xcode are trademarks of Apple Inc., registered in the United States and other countries. iPad and Retina are trademarks of Apple Inc. IOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license. Intel and Intel Core are registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries. OpenGL is a registered trademark of Silicon Graphics, Inc. Times is a registered trademark of Heidelberger Druckmaschinen AG, available from Linotype Library GmbH. UNIX is a registered trademark of The Open Group
Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION,
EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED AS IS, AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.
Contents
Introduction
Chapter 1
Chapter 2
Chapter 3
3
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
CONTENTS
The Main Run Loop 49 Background Execution and Multitasking 51 Determining Whether Multitasking Is Available 51 Executing a Finite-Length Task in the Background 52 Scheduling the Delivery of Local Notifications 53 Implementing Long-Running Background Tasks 54 Being a Responsible Background App 58 Opting out of Background Execution 59 Concurrency and Secondary Threads 60 Chapter 4
iCloud Storage 61
Design Considerations for iCloud Apps 61 Configuring Your Apps iCloud Entitlements 63 Using iCloud Document Storage 64 Determining if iCloud Document Storage is Available 66 Incorporating File Presenters into Your Workflow 66 Manipulating Files and Directories in iCloud 66 Choosing a Strategy to Respond to Version Conflicts 67 Incorporating Search into Your Infrastructure 68 Determining the Transfer Status of a File or Directory 69 Working With Files That Are Not Yet Downloaded 70 Updating Your User Interface for iCloud 70 Using iCloud in Conjunction with Databases 71 Using iCloud Key-Value Data Storage 74 Being a Responsible iCloud App 75
Chapter 5
App-Related Resources 77
App Store Required Resources 77 The Information Property List File 77 Declaring the Required Device Capabilities 78 Declaring Your Apps Supported Document Types 80 App Icons 81 App Launch (Default) Images 83 Providing Launch Images for Different Orientations 84 Providing Device-Specific Launch Images 85 Providing Launch Images for Custom URL Schemes 85 The Settings Bundle 86 Localized Resource Files 87
Chapter 6
4
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
CONTENTS
Adding Runtime Checks for Newer Symbols 91 Using Runtime Checks to Create Conditional Code Paths 91 Updating Your Resource Files 92 Preserving the State of Your Apps User Interface 92 Launching in Landscape Mode 93 Installing App-Specific Data Files at First Launch 94 Protecting Data Using On-Disk Encryption 94 Tips for Developing a VoIP App 95 Configuring Sockets for VoIP Usage 96 Installing a Keep-Alive Handler 97 Configuring Your Apps Audio Session 97 Using the Reachability Interfaces to Improve the User Experience 98 Communicating with Other Apps 98 Implementing Custom URL Schemes 99 Registering Custom URL Schemes 99 Handling URL Requests 100 Showing and Hiding the Keyboard 104 Turning Off Screen Locking 104 Chapter 7
Appendix A
5
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
CONTENTS
6
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
Chapter 3
Chapter 4
iCloud Storage 61
Figure 4-1 Table 4-1 Pushing document changes to iCloud 65 Differences between document and key-value storage 62
Chapter 5
App-Related Resources 77
Figure 5-1 Table 5-1 Table 5-2 Table 5-3 Table 5-4 Custom preferences displayed by the Settings app 86 Dictionary keys for the UIRequiredDeviceCapabilities key 79 Sizes for images in the CFBundleIconFiles key 82 Typical launch image dimensions 83 Launch image orientation modifiers 84
7
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
Chapter 6
Chapter 7
Appendix A
8
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
INTRODUCTION
This document is the starting point for creating iOS apps. It describes the fundamental architecture of iOS apps, including how the code you write fits together with the code provided by iOS. This document also offers practical guidance to help you make better choices during your design and planning phase and guides you to the other documents in the iOS developer library that contain more detailed information about how to address a specific task.
The contents of this document apply to all iOS apps running on all types of iOS devices, including iPad, iPhone, and iPod touch.
9
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
INTRODUCTION
Note: Development of iOS apps requires an Intel-based Macintosh computer with the iOS SDK installed.
At a Glance
The starting point for any new app is identifying the design choices you need to make and understanding how those choices map to an appropriate implementation.
10
At a Glance
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
INTRODUCTION
At a Glance
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
11
INTRODUCTION
Prerequisites
This document is the main entry-point guide for designing an iOS app. This guide also covers many of the practical aspects involved with implementing your app. However, this book assumes that you have already installed the iOS SDK and configured your development environment. You must perform those steps before you can start writing and building iOS apps. If you are new to iOS app development and want an overview of iOS development process, including information about how to configure your development environment, see App Development Overview.
See Also
For additional information related to app design, see the following documents:
For guidance about how to design an iOS app, read iOS Human Interface Guidelines. This book provides you with tips and guidance about how to create a great experience for users of your app. It also conveys the basic design philosophy surrounding iOS apps. If you are not sure what is possible in an iOS app, read iOS Technology Overview. This book provides a summary of iOS technologies and the situations where you might want to use them. This book is not required reading but is a good reference during the brainstorming phase of your project.
12
INTRODUCTION
If you are interested in a more hands-on approach to creating iOS apps, you should read Your First iOS App. This tutorial walks you through the app-creation process from start to finish, showing you how to create a simple app and get it running.
See Also
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
13
INTRODUCTION
14
See Also
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
CHAPTER 1
If you are a new to developing iOS apps, you might be wondering where the app development process starts. After devising your initial idea for an app, you need to turn that idea into an action plan for implementing your app. From a design perspective, you need to make some high-level decisions about the best course of action for implementing your ideas. You also need to set up your initial Xcode project in a way that makes it easy to proceed with development. If you are new to developing iOS apps altogether, spend some time familiarizing yourself with the basic concepts. There are tutorials to help you jump right in if you want to start writing code, but iOS is a system built from basic design patterns. Taking a little bit of time to learn those patterns will help you tremendously later.
15
CHAPTER 1
Model-View-ControllerThis design pattern governs the overall structure of your app. DelegationThis design pattern facilitates the transfer information and data from one object to another. Target-actionThis design pattern translates user interactions with buttons and controls into code that your app can execute. Block objectsYou use blocks to implement callbacks and asynchronous code. SandboxingAll iOS apps are placed in sandboxes to protect the system and other apps. The structure of the sandbox affects the placement of your apps files and has implications for data backups and some app-related features.
Accurate and efficient memory management is important for iOS apps. Because iOS apps typically have less usable memory than a comparable desktop computer, apps need to be aggressive about deleting unneeded objects and be lazy about creating objects in the first place. Apps that use the compilers Automatic Reference Counting (ARC) feature already get a very efficient way of managing memory that is similar to garbage collection but without many of the performance penalties. If you are not using ARC, you must manage memory yourself by explicitly retaining and releasing objects. There are other design patterns that you might see used occasionally or use yourself in your own code. For a complete overview of the design patterns and techniques you will use to create iOS apps, see Cocoa Fundamentals Guide.
Existing data model codeIf you already have data model code written in a C-based language, you can integrate that code directly into your iOS apps. Because iOS apps are written in Objective-C, they work just fine with code written in other C-based languages. Of course, there is also benefit to writing an Objective-C wrapper for any non Objective-C code. Custom objects data modelA custom object typically combines some simple data (strings, numbers, dates, URLs, and so on) with the business logic needed to manage that data and ensure its consistency. Custom objects can store a combination of scalar values and pointers to other objects. For example, the Foundation framework defines classes for many simple data types and for storing collections of other objects. These classes make it much easier to define your own custom objects. Structured data modelIf your data is highly structuredthat is, it lends itself to storage in a databaseuse Core Data (or SQLite) to store the data. Core Data provides a simple object-oriented model for managing your structured data. It also provides built-in support for some advanced features like undo and iCloud. (SQLite files cannot be used in conjunction with iCloud.)
16
CHAPTER 1
The job of a document is to manage your apps in-memory data model objects and coordinate the storage of that data in a corresponding file (or set of files) on disk. Documents normally connote files that the user created but apps can use documents to manage non user facing files too. One big advantage of using documents is that the UIDocument class makes interacting with iCloud and the local file system much simpler. For apps that use Core Data to store their content, the UIManagedDocument class provides similar support.
Building block approachThe easiest way to create your user interface is to assemble it using existing view objects. Views represent visual elements such as tables, buttons, text fields, and so on. You use many views as-is but you can also customize the appearance and behavior of standard views as needed to meet your needs. You can also implement new visual elements using custom views and mix those views freely with the standard views in your interface. The advantages of views are that they provide a consistent user experience and they allow you to define complex interfaces quickly and with relatively little code. OpenGL ES-based approachIf your app requires frequent screen updates or sophisticated rendering, you probably need to draw that content directly using OpenGL ES. The main use of OpenGL ES is for games and apps that rely heavily on sophisticated graphics, and therefore need the best performance possible.
What is the basic interface-style of your app? Different types of app require different sets of initial views and view controllers. Knowing how you plan to organize your user interface lets you select an initial project template that is most suited to your needs. You can always change your user interface later, but choosing the most appropriate template first makes starting your project much easier. Do you want to create a Universal app or one targeted specifically for iPad or iPhone? Creating a universal app requires specifying different sets of views and view controllers for iPad and iPhone and dynamically selecting the appropriate set at runtime. Universal apps are preferred because they support more iOS devices but do require you to factor your code better for each platform. For information about how a universal app affects the code you write, see Creating a Universal App (page 89). Do you want your app to use storyboards? Storyboards simplify the design process by showing both the views and view controllers of your user interface and the transitions between them. Storybards are supported in iOS 5 and later and are enabled by default for new projects. If your app must run on earlier versions of iOS, though, you cannot use storyboards and should continue to use nib files. Do you want to use Core Data for your data model? Some types of apps lend themselves naturally to a structured data model, which makes them ideal candidates for using Core Data. For more information about Core Data and the advantages it offers, see Core Data Programming Guide.
17
CHAPTER 1
From these questions, you can use Xcode to create your initial project files and start coding. 1. If you have not yet installed Xcode, do so and configure your iOS development team. For detailed information about setting up your development teams and and preparing your Xcode environment, see App Development Overview. Create your initial Xcode project. Before writing any code, build and run your new Xcode project. Target your app for iOS Simulator so that you can see it run. Every new Xcode project starts you with a fully functional (albeit featureless) app. The app itself should run and display the default views found in the main storyboard or nib file, which are probably not very interesting. The reason that the app runs at all, though, is because of the infrastructure provided to you by UIKit. This infrastructure initializes the app, loads the initial interface file, and checks the app in with the system so that it can start handling events. For more information about this infrastructure and the capabilities it provides, see The Core Objects of Your App (page 21) and The App Launch Cycle (page 37). 4. Start writing your apps primary code. For new apps, you probably want to start creating the classes associated with your apps data model first. These classes usually have no dependencies on other parts of your app and should be something you can work on initially. For information about ways to build your data model, see The Data Model (page 24). You might also want to start playing around with designs for your user interface by adding views to your main storyboard or nib file. From these views, you can also start identifying the places in your code where you need to respond to interface-related changes. For an overview of user interfaces and where they fit into your apps code, see The User Interface (page 28). If your app supports iCloud, you should incorporate support for iCloud into your classes at an early stage. For information about adding iCloud support to your app, see iCloud Storage (page 61). 5. Add support for app state changes. In iOS, the state of an app determines what it is allowed to do and when. App states are managed by high-level objects in your app but can affect many other objects as well. Therefore, you need to consider how the current app state affects your data model and view code and update that code appropriately. For information about app states and how apps run in the foreground and background, see App States and Multitasking (page 35) 6. Create the resources needed to support your app. Apps submitted to the App Store are expected to have specific resources such as icons and launch images to make the overall user experience better. Well-factored apps also make heavy use of resource files to keep their code separate from the data that code manipulates. This factoring makes it much easier to localize your app, tweak its appearance, and perform other tasks without rewriting any code. For information about the types of resources found in a typical iOS app and how they are used, see The App Bundle (page 30) and App-Related Resources (page 77). 7. As needed, implement any app-specific behaviors that are relevant for your app. There are many ways to modify the way your app launches or interacts with the system. For information about the most common types of app customizations, see Advanced App Tricks (page 89).
2. 3.
18
CHAPTER 1
8.
Add the advanced features that make your app unique. iOS includes many other frameworks for managing multimedia, advanced rendering, game content, maps, contacts, location tracking, and many other advanced features. For an overview of the frameworks and features you can incorporate into your apps, see iOS Technology Overview.
9.
Do some basic performance tuning for your app. All iOS apps should be tuned for the best possible performance. Tuned apps run faster but also use system resources, such as memory and battery life, more efficiently. For information about areas to focus on during the tuning process, see Performance Tuning (page 105).
10. Iterate. App development is an iterative process. As you add new features, you might need to revisit some or all of the preceding steps to make adjustments to your existing code.
19
CHAPTER 1
20
CHAPTER 2
UIKit provides the infrastructure for all apps but it is your custom objects that define the specific behavior of your app. Your app consists of a handful of specific UIKit objects that manage the event loop and the primary interactions with iOS. Through a combination of subclassing, delegation, and other techniques, you modify the default behaviors defined by UIKit to implement your app. In addition to customizing the UIKit objects, you are also responsible for providing or defining other key sets of objects. The largest set of objects is your apps data objects, the definition of which is entirely your responsibility. You must also provide a set of user interface objects, but fortunately UIKit provides numerous classes to make defining your interface easy. In addition to code, you must also provide the resources and data files you need to deliver a shippable app.
21
CHAPTER 2
Figure 2-1
Data Objects
Document
View UIWindow
Event Loop
UIApplication You use the UIApplication object essentially as isthat is, without subclassing. This
object
controller object manages the app event loop and coordinates other high-level app behaviors. Your own custom app-level logic resides in your app delegate object, which works in tandem with this object. The app delegate is a custom object created at app launch time, usually by the UIApplicationMain function. The primary job of this object is to handle state transitions within the app. For example, this object is responsible for launch-time initialization and handling transitions to and from the background. For information about how you use the app delegate to manage state transitions, see Managing App State Changes (page 35). In iOS 5 and later, you can use the app delegate to handle other app-related events. The Xcode project templates declare the app delegate as a subclass of UIResponder. If the UIApplication object does not handle an event, it dispatches the event to your app delegate for processing. For more information about the types of events you can handle, see UIResponder Class Reference.
22
CHAPTER 2
Description Data model objects store your apps content and are specific to your app. For example, a banking app might store a database containing financial transactions, whereas a painting app might store an image object or even the sequence of drawing commands that led to the creation of that image. (In the latter case, an image object is still a data object because it is just a container for the image data.) Apps can also use document objects (custom subclasses of UIDocument) to manage some or all of their data model objects. Document objects are not required but offer a convenient way to group data that belongs in a single file or file package. For more information about documents, see Defining a Document-Based Data Model (page 27).
View controller objects manage the presentation of your apps content on screen. A view controller manages a single view and its collection of subviews. When presented, the view controller makes its views visible by installing them in the apps window. The UIViewController class is the base class for all view controller objects. It provides default functionality for loading views, presenting them, rotating them in response to device rotations, and several other standard system behaviors. UIKit and other frameworks define additional view controller classes to implement standard system interfaces such as the image picker, tab bar interface, and navigation interface. For detailed information about how to use view controllers, see View Controller Programming Guide for iOS.
UIWindow object A UIWindow object coordinates the presentation of one or more views on a screen.
Most apps have only one window, which presents content on the main screen, but apps may have an additional window for content displayed on an external display. To change the content of your app, you use a view controller to change the views displayed in the corresponding window. You never replace the window itself. In addition to hosting views, windows work with the UIApplication object to deliver events to your views and view controllers. View, control, Views and controls provide the visual representation of your apps content. A view is and layer objects an object that draws content in a designated rectangular area and responds to events within that area. Controls are a specialized type of view responsible for implementing familiar interface objects such as buttons, text fields, and toggle switches. The UIKit framework provides standard views for presenting many different types of content. You can also define your own custom views by subclassing UIView (or its descendants) directly. In addition to incorporating views and controls, apps can also incorporate Core Animation layers into their view and control hierarchies. Layer objects are actually data objects that represent visual content. Views use layer objects intensively behind the scenes to render their content. You can also add custom layer objects to your interface to implement complex animations and other types of sophisticated visual effects. What distinguishes one iOS app from another is the data it manages (and the corresponding business logic) and how it presents that data to the user. Most interactions with UIKit objects do not define your app but help you to refine its behavior. For example, the methods of your app delegate let you know when the app is changing states so that your custom code can respond appropriately.
23
CHAPTER 2
For information about the specific behaviors of a given class, see the corresponding class reference. For more information about how events flow in your app and information about your apps responsibilities at various points during that flow, see App States and Multitasking (page 35).
Description Strings in iOS are Unicode based. The string classes provide support for creating and manipulating strings in a variety of ways. The attributed string classes support stylized text and are used only in conjunction with Core Text.
Numbers
When you want to store numerical values in a collection, use number objects. The NSNumber class can represent integer, floating-point values, Booleans, and char types. The NSIndexPath class stores a sequence of numbers and is often used to specify multi-layer selections in hierarchical lists. For times when you need to store raw streams of bytes, use data objects. Data objects are also commonly used to store objects in an archived form. The NSValue class is typically extended (using categories) and used to archive common data types such as points and rectangles.
Raw bytes
24
CHAPTER 2
Classes
NSDate NSDateComponents NSURL
Description Use date objects to store timestamps, calendar dates, and other time-related information. In addition to their traditional use for referring to network resources, URLs in iOS are the preferred way to store paths to files. The NSURL class even provides support for getting and setting file-related attributes. Use collections to group related objects together in a single place. The Foundation framework provides several different types of collection classes
Collections
NSArray (NSMutableArray) NSDictionary (NSMutableDictionary) NSIndexSet (NSMutableIndexSet) NSOrderedSet (NSMutableOrderedSet) NSSet (NSMutableSet)
In addition to data-related objects, there are some other data types that are commonly used by the iOS frameworks to manage familiar types of data. You are encouraged to use these data types in your own custom objects to represent similar types of data.
NSInteger/NSUIntegerAbstractions for scalar signed and unsigned integers that define the integer
NSRangeA structure used to define a contiguous portion of a series. For example, you can use ranges
NSTimeIntervalThe number of seconds (whole and partial) in a given time interval. CGPointAn x and y coordinate value that defines a location. CGSizeCoordinate values that define a set of horizontal and vertical extents. CGRectCoordinate values that define a rectangular region.
Of course, when defining custom objects, you can always incorporate scalar values directly into your class implementations. In fact, a custom data object can include a mixture of scalar and object types for its member variables. Listing 2-1 shows a sample class definition for a collection of pictures. The class in this instance contains an array of images and a list of the indexes into that array representing the selected items. The class also contains a string for the collections title and a scalar Boolean variable indicating whether the collection is currently editable. Listing 2-1 Definition of a custom data object
@interface PictureCollection : NSObject { NSMutableOrderedSet* pictures; NSMutableIndexSet* selection; NSString* title; BOOL editable;
25
CHAPTER 2
} @property (nonatomic, strong) NSString * title; @property (nonatomic, readonly) NSOrderedSet* pictures; // Method definitions... @end
Note: When defining data objects, it is strongly recommended that you declare properties for any member variables that you to expose to clients of the object. Synthesizing these properties in your implementation file automatically creates appropriate accessor methods with the attributes you require. This ensures that object relationships are maintained appropriately and that objects are not released. Consider how undo operations on your custom objects might be handled. Supporting undo means being able to reverse changes made to your objects cleanly. If your objects incorporate complex business logic, you need to factor that logic in a way that can be undone easily. Here are some tips for implementing undo support in your custom objects:
Define the methods you need to make sure that changes to your object are symmetrical. For example, if you define a method to add an item, make sure you have a method for removing an item in a similar way. Factor out your business logic from the code you use to change the values of member variables. For multistep actions, use the current NSUndoManager object to group the steps together.
For more information about how to implement undo support in your app, see Undo Architecture. For more information about the classes of the Foundation framework, see Foundation Framework Reference.
Core Data provides an infrastructure for managing all the changes to your model objects. This gives you automatic support for undo and redo, and for maintaining reciprocal relationships between objects. It allows you to keep just a subset of your model objects in memory at any given time, which is very important for iOS apps. It uses a schema to describe the model objects. You define the principal features of your model classesincluding the relationships between themin a GUI-based editor. This provides a wealth of basic functionality for free, including setting of default values and attribute value validation. It allows you to maintain disjoint sets of edits of your objects. This is useful if you want to, for example, allow the user to make edits in one view that may be discarded without affecting data displayed in another view.
26
CHAPTER 2
It has an infrastructure for data store versioning and migration. This lets you easily upgrade an old version of the users file to the current version. It allows you to store your data in iCloud and access it from multiple devices.
For information about how to use Core Data, see Core Data Programming Guide.
Document
Document
Document
File
File
File
File system
You use the UIDocument class to implement document objects in your iOS app. This class provides the basic infrastructure needed to handle the file management aspects of the document. Other benefits of UIDocument include:
27
CHAPTER 2
It provides support for autosaving the document contents at appropriate times. It handles the required file coordination for documents stored in iCloud. It also provides hooks for resolving version conflicts. It provides support for undoing actions.
You must subclass UIDocument in order to implement the specific behavior required by your apps documents. For detailed information about how to implement a document-based app using UIDocument, see Document-Based Application Programming Guide for iOS.
28
CHAPTER 2
Note: You can also incorporate custom views into your UIKit view hierarchies. A custom view is a subclass of UIView in which you handle all of the drawing and event-handling tasks yourself. For more information about creating custom views and incorporating them into your view hierarchies, see View Programming Guide for iOS. Figure 2-3 shows the basic structure of an app whose interface is constructed solely using view objects. In this instance, the main view spans the visible area of the window (minus the scroll bar) and provides a simple white background. The main view also contains three subviews: an image view, a text view, and a button. Those subviews are what the app uses to present content to the user and respond to interactions. All of the views in the hierarchy are managed by a single view controller object. Figure 2-3 Building your interface using view objects
View Controller Application controller layer View layer Window View
Image View
Text View
Button
In a typical view-based app, you coordinate the onscreen views using your view controller objects. An app always has one view controller that is responsible for presenting all of the content on the screen. That view controller has a content view, which itself may contain other views. Some view controllers can also act as containers for content provided by other view controllers. For example, a split view controller displays the content from two view controllers side by side. Because view controllers play a vital role in view management, understand how they work and the benefits they provide by reading View Controller Programming Guide for iOS. For more information about views and the role they play in apps, see View Programming Guide for iOS.
29
CHAPTER 2
Figure 2-4 shows the configuration of an app that uses a single OpenGL ES view to draw its interface. Unlike a UIKit view, the OpenGL ES view is backed by a different type of layer object (a CAEAGLLayer object) instead of the standard layer used for view-based apps. The CAEAGLLayer object provides the drawing surface that OpenGL ES can render into. To manage the drawing environment, the app also creates an EAGLContext object and stores that object with the view to make it easy to retrieve. Figure 2-4 Building your interface using OpenGL ES
View Controller
(CAEAGLLayer)
View
EAGLContext
For information on how to configure OpenGL ES for use in your app, see OpenGL ES Programming Guide for iOS.
30
CHAPTER 2
Description The executable file contains your apps compiled code. The name of your apps executable file is the same as your app name minus the .app extension. This file is required.
Info.plist
The Info.plist file contains configuration data for the app. The system uses this data to determine how to interact with the app. This file is required and must be called Info.plist. For more information, see Figure 6-1 (page 100).
App icons
Your app icon is used to represent your app on the devices Home screen. Other icons are used by the system in appropriate places. Icons with @2x in their filename are intended for devices with Retina displays. An app icon is required. For information about specifying icon image files, see App Icons (page 81). The system uses this file as a temporary background while your app is launching. It is removed as soon as your app is ready to display its user interface. At least one launch image is required. For information about specifying launch images, see App Launch (Default) Images (page 83). Storyboards contain the views and view controllers that the app presents on screen. Views in a storyboard are organized according to the view controller that presents them. Storyboards also identify the transitions (called segues) that take the user from one set of views to another. The name of the main storyboard file is set by Xcode when you create your project. You can change the name by assigning a different value to the NSMainStoryboardFile key in the Info.plist file.) Apps that use nib files instead of storyboards can replace the NSMainStoryboardFile key with the NSMainNibFile key and use that key to specify their main nib file. The use of storyboards (or nib files) is optional but recommended.
MainBoard.storyboard
31
CHAPTER 2
Example
iTunesArtwork
Description If you are distributing your app ad hoc, include a 512 x 512 pixel version of your app icon. This icon is normally provided by the App Store from the materials you submit to iTunes Connect. However, because apps distributed ad hoc do not go through the App Store, your icon must be present in your app bundle instead. iTunes uses this icon to represent your app. (The file you specify should be the same one you would have submitted to the App Store, if you were distributing your app that way.) The filename of this icon must be iTunesArtwork and must not include a filename extension. This file is required for ad hoc distribution but is optional otherwise.
Settings bundle
Settings.bundle
If you want to expose custom app preferences through the Settings app, you must include a settings bundle. This bundle contains the property list data and other resource files that define your app preferences. The Settings app uses the information in this bundle to assemble the interface elements required by your app. This bundle is optional. For more information about preferences and specifying a settings bundle, see Preferences and Settings Programming Guide.
sun.png mydata.plist
Nonlocalized resources include things like images, sound files, movies, and custom data files that your app uses. All of these files should be placed at the top level of your app bundle. Localized resources must be placed in language-specific project directories, the names for which consist of an ISO 639-1 language abbreviation plus the .lproj suffix. (For example, the en.lproj, fr.lproj, and es.lproj directories contain resources localized for English, French, and Spanish.) An iOS app should be internationalized and have a language.lproj directory for each language it supports. In addition to providing localized versions of your apps custom resources, you can also localize your app icon, launch images, and Settings icon by placing files with the same name in your language-specific project directories. For more information, see Localized Resource Files (page 87).
From your code, access your apps resource files using an NSBundle object: 1. 2. 3. Use the mainBundle method of NSBundle to obtain your apps main bundle object. Use the methods of the bundle object to obtain the location of the desired resource file. Open (or access) the file and use it.
32
CHAPTER 2
The pathForResource:ofType: method is one of several NSBundle methods that you can use to retrieve the location of resource files in your bundle. The following example shows how to locate an image file called sun.png and create an image object. The first line gets the location of the file in the bundle. The second line creates the UIImage object using the data in the file at that location.
NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"sun" ofType:@"png"]; UIImage* sunImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
Note: Core Foundation also provides routines for accessing bundles. Use the CFBundleGetMainBundle function to obtain a CFBundleRef opaque type for your apps main bundle. You can then use the other bundle-related Core Foundation functions to locate your resource files. For information on how to access and use resources in your app, see Resource Programming Guide. For more information about the structure of an iOS app bundle, see Bundle Programming Guide.
33
CHAPTER 2
34
CHAPTER 3
For iOS apps, it is crucial to know whether your app is running in the foreground or the background. Because resources are more limited on iOS devices, an app must behave differently in the background than in the foreground. The operating system also limits what your app can do in the background in order to improve battery life and to improve the users experience with the foreground app. The operating system notifies your app whenever it moves between the foreground and background. These notifications are your chance to modify your apps behavior. While your app is in the foreground, the system sends touch events to it for processing. The UIKit infrastructure does most of the hard work of delivering events to your custom objects. All you have to do is override methods in the appropriate objects to process those events. For controls, UIKit simplifies things even further by handling the touch events for you and calling your custom code only when something interesting happens, such as when the value of a text field changes. As you implement your app, follow these guidelines:
(Required) Respond appropriately to the state transitions that occur. Not handling these transitions properly can lead to data loss and a bad user experience. For a summary of how to respond to state transitions, see Managing App State Changes (page 35). (Required) When moving to the background, make sure your app adjusts its behavior appropriately. For guidelines about what to do when your app moves to the background, see Being a Responsible Background App (page 58). (Recommended) Register for any notifications that report system changes your app needs. When an app is suspended, the system queues key notifications and delivers them when the app resumes execution. Apps should use these notifications to make a smooth transition back to execution. For more information, see Processing Queued Notifications at Wakeup Time (page 47). (Optional) If your app needs to do actual work while in the background, ask the system for the appropriate permissions to continue running. For more information about the types of background work you can do and how to request permission to do that work, see Background Execution and Multitasking (page 51).
35
CHAPTER 3
Not running The app has not been launched or was running but was terminated by the system. Inactive The app is running in the foreground but is currently not receiving events. (It may be executing other code though.) An app usually stays in this state only briefly as it transitions to a different state. The only time it stays inactive for any period of time is when the user locks the screen or the system prompts the user to respond to some event, such as an incoming phone call or SMS message. Active The app is running in the foreground and is receiving events. This is the normal mode for foreground apps.
Background The app is in the background and executing code. Most apps enter this state briefly on their way to being suspended. However, an app that requests extra execution time may remain in this state for a period of time. In addition, an app being launched directly into the background enters this state instead of the inactive state. For information about how to execute code while in the background, see Background Execution and Multitasking (page 51). Suspended The app is in the background but is not executing code. The system moves apps to this state automatically and does not notify them before doing so. While suspended, an app remains in memory but does not execute any code. When a low-memory condition occurs, the system may purge suspended apps without notice to make more space for the foreground app. Figure 3-1 State changes in an iOS app
Not running
Foreground Inactive
Active
Background Background
Suspended
36
CHAPTER 3
Note: Apps running in iOS 3.2 and earlier do not enter the background or suspended states. In addition, some devices do not support multitasking or background execution at all, even when running iOS 4 or later. Apps running on those devices also do not enter the background or suspended states. Instead, apps are terminated upon leaving the foreground. Most state transitions are accompanied by a corresponding call to the methods of your app delegate object. These methods are your chance to respond to state changes in an appropriate way. These methods are listed below, along with a summary of how you might use them.
at launch time.
applicationDidBecomeActive:This is your apps chance to prepare to run as the foreground app. applicationWillResignActive:Lets you know that your app is transitioning away from being
the foreground app. Use this method to put your app into a quiescent state.
applicationDidEnterBackground:Lets you know that your app is now running in the background
applicationWillEnterForeground:Lets you know that your app is moving out of the background
and back into the foreground, but that it is not yet active.
applicationWillTerminate:Lets you know that your app is being terminated. This method is not
37
CHAPTER 3
Figure 3-2
Launch Time
main()
UIApplicationMain()
Event Loop
Handle events
If your app is launched into the background insteadusually to handle some type of background eventthe launch cycle changes slightly to the one shown in Figure 3-3. The main difference is that instead of your app being made active, it enters the background state to handle the event and then is suspended shortly afterward. When launching into the background, the system still loads your apps user interface files but it does not display the apps window.
38
CHAPTER 3
Figure 3-3
main()
Your code
UIApplicationMain()
No
Allowed to run?
Yes
Monitor events
Handle events
To determine whether your app is launching into the foreground or background, check the applicationState property of the shared UIApplication object in your application:didFinishLaunchingWithOptions: method. When the app is launched into the foreground, this property contains the value UIApplicationStateInactive. When the app is launched into the background, the property contains the value UIApplicationStateBackground instead. You can use this difference to adjust the launch-time behavior of your application:didFinishLaunchingWithOptions: method accordingly.
39
CHAPTER 3
Note: When an app is launched so that it can open a URL, the sequence of startup events is slightly different from those shown in Figure 3-2 and Figure 3-3. For information about the startup sequences that occur when opening a URL, see Handling URL Requests (page 100).
#import <UIKit/UIKit.h> int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class])); } }
Note: An autorelease pool is used in memory management. It is a Cocoa mechanism used to defer the release of objects created during a functional block of code. For more information about autorelease pools, see Advanced Memory Management Programming Guide. The UIApplicationMain function takes four parameters and uses them to initialize the app. You should never have to change the default values passed into this function. Still, it is valuable to understand their purpose and how they start the app.
The argc and argv parameters contain any launch-time arguments passed to the app from the system. These arguments are parsed by the UIKit infrastructure and can otherwise be ignored. The third parameter identifies the name of the principal app class. This is the class responsible for running the app. It is recommend that you specify nil for this parameter, which causes UIKit to use the UIApplication class. The fourth parameter identifies the class of your custom app delegate. Your app delegate is responsible for managing the high-level interactions between the system and your code. The Xcode template projects set this parameter to an appropriate value automatically.
Another thing the UIApplicationMain function does is load the apps main user interface file. The main interface file contains the initial view-related objects you plan to display in your apps user interface. For apps that use storyboards, this function loads the initial view controller from your storyboard and installs it in the window provided by your app delegate. For apps that use nib files, the function loads the nib file contents into memory but does not install them in your apps window. You must install them yourself in the application:didFinishLaunchingWithOptions: method of your app delegate.
40
CHAPTER 3
An app can have either a main storyboard file or a main nib file but cannot have both. Storyboards, the preferred way to specify your apps user interface, are not supported on all versions of iOS. Specify the name of your main storyboard file in the UIMainStoryboardFile key of your apps Info.plist file. (For nib-based apps, specify the name of your main nib file using the NSMainNibFile key instead.) Normally, Xcode sets the value of this key when you create your project, but you can change it later if needed. For more information about the Info.plist file and how you use it to configure your app, see Figure 6-1 (page 100).
Check the contents of the launch options dictionary for information about why the app was launched, and respond appropriately. Initialize the apps critical data structures. Prepare your apps window and views for display. Apps that use OpenGL ES should not use this method to prepare their drawing environment. Instead, they should defer any OpenGL ES drawing calls to the applicationDidBecomeActive: method.
Use any saved preferences or state information to restore the app to its previous runtime state.
If your app uses nib files to manage its views, you should use the application:didFinishLaunchingWithOptions: method to prepare your apps window for display. For nib-based apps, you must create your window object, install the views from your initial view controller, and show the window. For apps that support both portrait and landscape orientations, always set up your window in a portrait orientation. If the device is in a different orientation at launch time, the system automatically rotates your views to the appropriate orientation before displaying the window. Your application:didFinishLaunchingWithOptions: method should always be as lightweight as possible to reduce your apps launch time. Apps are expected to launch and initialize themselves and start handling events in roughly 5 seconds. If an app does not finish its launch cycle in a timely manner, the system kills it for being unresponsive. Thus, any tasks that might slow down your launch (such as accessing the network) should be executed asynchronously on a secondary thread. When launching into the foreground, the system also calls the applicationDidBecomeActive: method to finish the transition to the foreground. Because this method is called both at launch time and when transitioning from the background, use it to perform any tasks that are common to the two transitions. When launching into the background, there should not be much for your app to do except get ready to handle whatever event arrived.
41
CHAPTER 3
Responding to Interruptions
When an alert-based interruption occurs, such as an incoming phone call, the app moves temporarily to the inactive state so that the system can prompt the user about how to proceed. The app remains in this state until the user dismiss the alert. At this point, the app either returns to the active state or moves to the background state to make way for another app. Figure 3-4 shows the flow of events through your app when an alert-based interruption occurs. Figure 3-4
Foreground
Event Loop
applicationWillResignActive:
Ignore?
No
Yes
applicationDidBecomeActive:
In iOS 5, notifications that display a banner do not deactivate your app in the way that alert-based notifications do. Instead, the banner is laid along the top edge of your app window and your app continues receive touch events as before. However, if the user pulls down the banner to reveal the notification center, your app moves to the inactive state just as if an alert-based interruption had occurred. Your app remains in the inactive state until the user dismisses the notification center or launches another app. At this point, your app moves to the appropriate active or background state. The user can use the Settings app to configure which notifications display a banner and which display an alert. Pressing the Sleep/Wake button is another type of interruption that causes your app to be deactivated. When the user presses this button, the system disables touch events, deactivates your app, and locks the screen. A locked screen has additional consequences for apps that use data protection to encrypt files. Those consequences are described in What to Do When an Interruption Occurs (page 42).
42
CHAPTER 3
Stop timers and other periodic tasks. Stop any running metadata queries. Do not initiate any new tasks. Pause movie playback (except when playing back over AirPlay). Games should enter into a pause state. Throttle back OpenGL ES frame rates. Suspend any dispatch queues or operation queues executing non-critical code. (You can continue processing network requests and other time-sensitive background tasks while inactive.)
When your app is moved back to the active state, its applicationDidBecomeActive: method should reverse any of the steps taken in the applicationWillResignActive: method. Thus, upon reactivation, your app should restart timers, resume any dispatch queues, and throttle up OpenGL ES frame rates again. However, games should not resume automatically; they should remain paused until the user decides to resume them. When the user presses the Sleep/Wake button, apps with files protected by the NSFileProtectionComplete protection option must close any references to those files. For devices configured with an appropriate password, pressing the Sleep/Wake button locks the screen and forces the system to throw away the decryption keys for files with complete protection enabled. While the screen is locked, any attempts to access the corresponding files will fail. So if you have such files, you should close any references to them in your applicationWillResignActive: method and open new references in your applicationDidBecomeActive: method.
43
CHAPTER 3
Figure 3-5
No
Allowed to run?
Yes
Monitor events
Handle events
Memory pressure
Terminate app
Note: Apps are moved to the background only on devices that support multitasking and only if those devices are running iOS 4.0 or later. In all other cases, the app is terminated (and thus purged from memory) instead of moved to the background.
Prepare to have their picture taken. When the applicationDidEnterBackground: method returns, the system takes a picture of your apps user interface and uses the resulting image for transition animations. If any views in your interface contain sensitive information, you should hide or modify those views before the applicationDidEnterBackground: method returns.
44
CHAPTER 3
Save user data and app state information. All unsaved changes should be written to disk when entering the background. This step is necessary because your app might be quietly killed while in the background for any number of reasons. You can perform this operation from a background thread as needed. Free up as much memory as possible. For more information about what to do and why this is important, see Memory Usage for Background Apps (page 45).
Your app delegates applicationDidEnterBackground: method has approximately 5 seconds to finish any tasks and return. In practice, this method should return as quickly as possible. If the method does not return before time runs out, your app is killed and purged from memory. If you still need more time to perform tasks, call the beginBackgroundTaskWithExpirationHandler: method to request background execution time and then start any long-running tasks in a secondary thread. Regardless of whether you start any background tasks, the applicationDidEnterBackground: method must still exit within 5 seconds. Note: The UIApplicationDidEnterBackgroundNotification notification is also sent to let interested parts of your app know that it is entering the background. Objects in your app can use the default notification center to register for this notification. Depending on the features of your app, there are other things your app should do when moving to the background. For example, any active Bonjour services should be suspended and the app should stop calling OpenGL ES functions. For a list of things your app should do when moving to the background, see Being a Responsible Background App (page 58).
Cached image objects Large media or data files that you can load again from disk Any other objects that your app does not need and can recreate easily later
To help your app reduce its memory footprint, the system automatically releases many of the objects used behind the scenes to support your app. For example:
It releases the backing store for all Core Animation layers, which prevents the contents of those layers from appearing onscreen but does not change the current layer properties. It does not release the layer objects themselves. It removes any references to cached images. (If your app does not have a strong reference to the images, they are subsequently removed from memory.)
45
CHAPTER 3
Event Loop
Handle events
46
CHAPTER 3
Note: The UIApplicationWillEnterForegroundNotification notification is also available for tracking when your app reenters the foreground. Objects in your app can use the default notification center to register for this notification.
UIDeviceOrientationDidChangeNotification
In addition to this notification, view controllers update their interface orientations automatically. There is a significant time change. The battery level or battery state changes.
UIApplicationSignificantTimeChangeNotification UIDeviceBatteryLevelDidChangeNotification UIDeviceBatteryStateDidChangeNotification
An external display is connected or disconnected. The screen mode of a display changes. Preferences that your app exposes through the Settings app changed. The current language or locale settings changed.
NSCurrentLocaleDidChangeNotification
47
CHAPTER 3
Queued notifications are delivered on your apps main run loop and are typically delivered before any touch events or other user input. Most apps should be able to handle these events quickly enough that they would not cause any noticeable lag when resumed. However, if your app appears sluggish when it returns from the background state, use Instruments to determine whether your notification handler code is causing the delay. An app returning to the foreground also receives view-update notifications for any views that were marked dirty since the last update. An app running in the background can still call the setNeedsDisplay or setNeedsDisplayInRect: methods to request an update for its views. However, because the views are not visible, the system coalesces the requests and updates the views only after the app returns to the foreground.
Use the autoupdatingCurrentLocale class method when retrieving NSLocale objects. This method returns a locale object that updates itself automatically in response to changes, so you never need to recreate it. However, when the locale changes, you still need to refresh views that contain content derived from the current locale. Re-create any cached date and number formatter objects whenever the current locale information changes.
For more information about internationalizing your code to handle locale changes, see Internationalization Programming Topics.
App Termination
Although apps are generally moved to the background and suspended, if any of the following conditions are true, your app is terminated and purged from memory instead:
48
CHAPTER 3
The app is linked against a version of iOS earlier than 4.0. The app is deployed on a device running a version of iOS earlier than 4.0. The current device does not support multitasking; see Determining Whether Multitasking Is Available (page 51). The app includes the UIApplicationExitsOnSuspend key in its Info.plist file; see Opting out of Background Execution (page 59).
If your app is running (either in the foreground or background) at termination time, the system calls your app delegates applicationWillTerminate: method so that you can perform any required cleanup. You can use this method to save user data or app state information that you would use to restore your app to its current state on a subsequent launch. Your method has approximately 5 seconds to perform any tasks and return. If it does not return in time, the app is killed and removed from memory. Important: The applicationWillTerminate: method is not called if your app is currently suspended. Even if you develop your app using iOS SDK 4 and later, you must still be prepared for your app to be killed without any notification. The user can kill apps explicitly using the multitasking UI. In addition, if memory becomes constrained, the system might remove apps from memory to make more room. Suspended apps are not notified of termination but f your app is currently running in the background state (and not suspended), the system calls the applicationWillTerminate: method of your app delegate. Your app cannot request additional background execution time from this method.
49
CHAPTER 3
Figure 3-7
Event source Port Event queue Main run loop Operating system
Application object
Core objects
Many types of events can be delivered in an iOS app. The most common ones are listed in Table 3-3. Many of these event types are delivered using the main run loop of your app, but some are not. For example, accelerometer events are delivered directly to the accelerometer delegate object that you specify. For information about how to handle most types of eventsincluding touch, remote control, motion, accelerometer, and gyroscopic eventssee Event Handling Guide for iOS. Table 3-3 Event type Touch Common types of events for iOS apps Delivered to The view object in which the event occurred Notes Views are responder objects. Any touch events not handled by the view are forwarded down the responder chain for processing. Remote control events are for controlling media playback and are generated by headphones and other accessories. Motion events reflect specific motion-related events (such as shaking a device) and are handled separately from other accelerometer-based events. . Events related to the accelerometer and gyroscope hardware are delivered to the object you designate. Redraw events do not involve an event object but are simply calls to the view to draw itself. The drawing architecture for iOS is described in Drawing and Printing Guide for iOS.
Motion
50
CHAPTER 3
Notes You register to receive location events using the Core Location framework. For more information about using Core Location, see Location Awareness Programming Guide.
Some events, such as touch and remote control events, are handled by your apps responder objects. Responder objects are everywhere in your app. (The UIApplication object, your view objects, and your view controller objects are all examples of responder objects.) Most events target a specific responder object but can be passed to other responder objects (via the responder chain) if needed to handle an event. For example, a view that does not handle an event can pass the event to its superview or to a view controller. Touch events occurring in controls (such as buttons) are handled differently than touch events occurring in many other types of views. There are typically only a limited number of interactions possible with a control, and so those interactions are repackaged into action messages and delivered to an appropriate target object. This target-action design pattern makes it easy to use controls to trigger the execution of custom code in your app.
You need to implement at least one of several specific user services. You need to perform a single finite-length task. You need to use notifications to alert the user to some relevant piece of information when your app is not running.
The system keeps suspended apps in memory for as long as possible, removing them only when the amount of free memory gets low. Remaining in memory means that subsequent launches of your app are much faster. At the same time, being suspended means your app does not drain the devices battery as fast.
51
CHAPTER 3
If the presence or absence of multitasking changes the way your app behaves, check the multitaskingSupported property of the UIDevice class to determine whether multitasking is available before performing the relevant task. For apps built for iOS 4 and later, this property is always available. However, if your app supports earlier versions of the system, you must check to see whether the property itself is available before accessing it, as shown in Listing 3-2. Listing 3-2 Checking for background support in earlier versions of iOS
UIDevice* device = [UIDevice currentDevice]; BOOL backgroundSupported = NO; if ([device respondsToSelector:@selector(isMultitaskingSupported)]) backgroundSupported = device.multitaskingSupported;
- (void)applicationDidEnterBackground:(UIApplication *)application { UIApplication* app = [UIApplication sharedApplication]; bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ // Clean up any unfinished task business by marking where you. // stopped or ending the task outright. [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid;
52
CHAPTER 3
}]; // Start the long-running task and return immediately. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Do the work associated with the task, preferably in chunks. [app endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }); }
Note: Always provide an expiration handler when starting a task, but if you want to know how much time your app has left to run, get the value of the backgroundTimeRemaining property of UIApplication. In your own expiration handlers, you can include additional code needed to close out your task. However, any code you include must not take too long to execute because, by the time your expiration handler is called, your app is already very close to its time limit. For this reason, perform only minimal cleanup of your state information and end the task.
- (void)scheduleAlarmForDate:(NSDate*)theDate { UIApplication* app = [UIApplication sharedApplication]; NSArray* oldNotifications = [app scheduledLocalNotifications]; // Clear out the old notification before scheduling a new one. if ([oldNotifications count] > 0)
53
CHAPTER 3
[app cancelAllLocalNotifications]; // Create a new notification. UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease]; if (alarm) { alarm.fireDate = theDate; alarm.timeZone = [NSTimeZone defaultTimeZone]; alarm.repeatInterval = 0; alarm.soundName = @"alarmsound.caf"; alarm.alertBody = @"Time to wake up!"; [app scheduleLocalNotification:alarm]; } }
Sound files used with local notifications have the same requirements as those used for push notifications. Custom sound files must be located inside your apps main bundle and support one of the following formats: Linear PCM, MA4, -Law, or a-Law. You can also specify the sound name default to play the default alert sound for the device. When the notification is sent and the sound is played, the system also triggers a vibration on devices that support it. You can cancel scheduled notifications or get a list of notifications using the methods of the UIApplication class. For more information about these methods, see UIApplication Class Reference. For additional information about configuring local notifications, see Local and Push Notification Programming Guide.
Apps that play audible content to the user while in the background, such as a music player app Apps that keep users informed of their location at all times, such as a navigation app Apps that support Voice over Internet Protocol (VoIP) Newsstand apps that need to download and process new content Apps that receive regular updates from external accessories
Apps that implement these services must declare the services they support and use system frameworks to implement the relevant aspects of those services. Declaring the services lets the system know which services you use, but in some cases it is the system frameworks that actually prevent your application from being suspended.
54
CHAPTER 3
audioThe app plays audible content to the user while in the background. (This content includes
locationThe app keeps users informed of their location, even while it is running in the background. voipThe app provides the ability for the user to make phone calls using an Internet connection. newsstand-contentThe app is a Newsstand app that downloads and processes magazine or
external-accessoryThe app works with a hardware accessory that needs to deliver updates on a
regular schedule. Each of the preceding values lets the system know that your app should be woken up at appropriate times to respond to relevant events. For example, an app that begins playing music and then moves to the background still needs execution time to fill the audio output buffers. Including the audio key tells the system frameworks that they should continue playing and make the necessary callbacks to the app at appropriate intervals. If the app does not include this key, any audio being played by the app stops when the app moves to the background.
The significant-change location service (Recommended) Foreground-only location services Background location services
The significant-change location service is highly recommended for apps that do not need high-precision location data. With this service, location updates are generated only when the users location changes significantly; thus, it is ideal for social apps or apps that provide the user with noncritical, location-relevant information. If the app is suspended when an update occurs, the system wakes it up in the background to handle the update. If the app starts this service and is then terminated, the system relaunches the app automatically when a new location becomes available. This service is available in iOS 4 and later, and it is available only on devices that contain a cellular radio. The foreground-only and background location services both use the standard location Core Location service to retrieve location data. The only difference is that the foreground-only location services stop delivering updates if the app is ever suspended, which is likely to happen if the app does not support other background services or tasks. Foreground-only location services are intended for apps that only need location data while they are in the foreground. An app that provides continuous location updates to the user (even when in the background) can enable background location services by including the UIBackgroundModes key (with the location value) in its Info.plist file. The inclusion of this value in the UIBackgroundModes key does not preclude the system from suspending the app, but it does tell the system that it should wake up the app whenever there is new location data to deliver. Thus, this key effectively lets the app run in the background to process location updates whenever they occur.
55
CHAPTER 3
Important: You are encouraged to use the standard services sparingly or use the significant location change service instead. Location services require the active use of an iOS devices onboard radio hardware. Running this hardware continuously can consume a significant amount of power. If your app does not need to provide precise and continuous location information to the user, it is best to minimize the use of location services. For information about how to use each of the different location services in your app, see Location Awareness Programming Guide.
Music player apps Apps that support audio or video playback over AirPlay VoIP apps
When the UIBackgroundModes key contains the audio value, the systems media frameworks automatically prevent the corresponding app from being suspended when it moves to the background. As long as it is playing audio or video content, the app continues to run in the background. However, if the app stops playing the audio or video, the system suspends it. You can use any of the system audio frameworks to initiate the playback of background audio, and the process for using those frameworks is unchanged. (For video playback over AirPlay, you must use the Media Player framework to present your video.) Because your app is not suspended while playing media files, callbacks operate normally while your app is in the background. In your callbacks, though, you should do only the work necessary to provide data for playback. For example, a streaming audio app would need to download the music stream data from its server and push the current audio samples out for playback. You should not perform any extraneous tasks that are unrelated to playback. Because more than one app may support audio, the system limits which apps can play audio at any given time. The foreground app always has permission to play audio. In addition, one or more background apps may also be allowed to play some audio content depending on the configuration of their audio session objects. You should always configure your apps audio session object appropriately and work carefully with the system frameworks to handle interruptions and other types of audio-related notifications. For information on how to configure audio session objects for background execution, see Audio Session Programming Guide.
56
CHAPTER 3
To configure a VoIP app, you must do the following: 1. Add the UIBackgroundModes key to your apps Info.plist file. Set the value of this key to an array that includes the voip value. Configure one of the apps sockets for VoIP usage. Before moving to the background, call the setKeepAliveTimeout:handler: method to install a handler to be executed periodically. Your app can use this handler to maintain its service connection. Configure your audio session to handle transitions to and from active use.
2. 3.
4.
Including the voip value in the UIBackgroundModes key lets the system know that it should allow the app to run in the background as needed to manage its network sockets. An app with this key is also relaunched in the background immediately after system boot to ensure that the VoIP services are always available. Most VoIP apps also need to be configured as background audio apps to deliver audio while in the background. Therefore, you should include both the audio and voip values to the UIBackgroundModes key. If you do not do this, your app cannot play audio while it is in the background. For more information about the UIBackgroundModes key, see Information Property List Key Reference. For specific information about the steps you must take to implement a VoIP app, see Tips for Developing a VoIP App (page 95).
57
CHAPTER 3
Apps must provide an interface that allows the user to start and stop the delivery of accessory update events. That interface should then open or close the accessory session as appropriate. Upon being woken up, the app has around 10 seconds to process the data. Ideally, it should process the data as fast as possible and allow itself to be suspended again. However, if more time is needed, the app can use the beginBackgroundTaskWithExpirationHandler: method to request additional time; it should do so only when absolutely necessary, though.
Do not make any OpenGL ES calls from your code. You must not create an EAGLContext object or issue any OpenGL ES drawing commands of any kind while running in the background. Using these calls causes your app to be killed immediately. Apps must also ensure that any previously submitted commands have completed before moving to the background. For information about how to handle OpenGL ES when moving to and from the background, see Implementing a Multitasking-aware OpenGL ES Application in OpenGL ES Programming Guide for iOS. Cancel any Bonjour-related services before being suspended. When your app moves to the background, and before it is suspended, it should unregister from Bonjour and close listening sockets associated with any network services. A suspended app cannot respond to incoming service requests anyway. Closing out those services prevents them from appearing to be available when they actually are not. If you do not close out Bonjour services yourself, the system closes out those services automatically when your app is suspended. Be prepared to handle connection failures in your network-based sockets. The system may tear down socket connections while your app is suspended for any number of reasons. As long as your socket-based code is prepared for other types of network failures, such as a lost signal or network transition, this should not lead to any unusual problems. When your app resumes, if it encounters a failure upon using a socket, simply reestablish the connection. Save your app state before moving to the background. During low-memory conditions, background apps may be purged from memory to free up space. Suspended apps are purged first, and no notice is given to the app before it is purged. As a result, before moving to the background, an app should always save enough state information to reconstitute itself later if necessary. For tips on how to save the state of your user interface, see Preserving the State of Your Apps User Interface (page 92). Release any unneeded memory when moving to the background. If your app maintains a large in-memory cache of objects (especially images), remove references to those caches when moving to the background. For more information, see Memory Usage for Background Apps (page 45). Stop using shared system resources before being suspended. Apps that interact with shared system resources such as the Address Book or calendar databases should stop using those resources before being suspended. Priority for such resources always goes to the foreground app. When your app is suspended, if it is found to be using a shared resource, the app is killed.
58
CHAPTER 3
Avoid updating your windows and views. While in the background, your apps windows and views are not visible, so you should not try to update them. Although creating and manipulating window and view objects in the background does not cause your app to be killed, consider postponing this work until you return to the foreground. Respond to connect and disconnect notifications for external accessories. For apps that communicate with external accessories, the system automatically sends a disconnection notification when the app moves to the background. The app must register for this notification and use it to close out the current accessory session. When the app moves back to the foreground, a matching connection notification is sent, giving the app a chance to reconnect. For more information on handling accessory connection and disconnection notifications, see External Accessory Programming Topics. Clean up resources for active alerts when moving to the background. In order to preserve context when switching between apps, the system does not automatically dismiss action sheets (UIActionSheet) or alert views (UIAlertView) when your app moves to the background. It is up to you to provide the appropriate cleanup behavior prior to moving to the background. For example, you might want to cancel the action sheet or alert view programmatically or save enough contextual information to restore the view later (in cases where your app is terminated). For apps linked against a version of iOS earlier than 4.0, action sheets and alerts are still dismissed at quit time so that your apps cancellation handler has a chance to run.
Remove sensitive information from views before moving to the background. When an app transitions to the background, the system takes a snapshot of the apps main window, which it then presents briefly when transitioning your app back to the foreground. Before returning from your applicationDidEnterBackground: method, you should hide or obscure passwords and other sensitive personal information that might be captured as part of the snapshot. Do minimal work while running in the background. The execution time given to background apps is more constrained than the amount of time given to the foreground app. If your app plays background audio or monitors location changes, you should focus on that task only and defer any nonessential tasks until later. Apps that spend too much time executing in the background can be throttled back by the system or killed.
If you are implementing a background audio app, or any other type of app that is allowed to run in the background, your app responds to incoming messages in the usual way. In other words, the system may notify your app of low-memory warnings when they occur. And in situations where the system needs to terminate apps to free even more memory, the app calls its delegates applicationWillTerminate: method to perform any final tasks before exiting.
59
CHAPTER 3
cannot easily release any of it, the system might need to kill your app quickly anyway to make room for other apps. Thus, opting to terminate, instead of switching to the background, might yield the same results and save you development time and effort. Note: Explicitly opting out of background execution is necessary only if your app is linked against iOS SDK 4 and later. Apps linked against earlier versions of the SDK do not support background execution as a rule and therefore do not need to opt out explicitly. For more information about the keys you can include in your apps Info.plist file, see Information Property List Key Reference.
60
CHAPTER 4
iCloud Storage
iCloud storage is a set of interfaces and services for sharing data among instances of your app running on different devices. The idea behind iCloud is to provide a single place where your app can write its data. Changes made by one instance of your app are propagated to the users other devices seamlessly so that the other instances of your app see them too. This creates a more coherent user experience by eliminating the need to synchronize data explicitly between devices or have a computer act as a hub for storing all of the users files and data. There are two ways to adopt iCloud storage in your app:
iCloud document storageUse this feature to store user documents and app data in the users iCloud account. iCloud key-value data storageUse this feature to share small amounts of noncritical configuration data among instances of your app.
Most of the iCloud interfaces are aimed at helping you manage files, not your user interface. Adopting iCloud storage requires some changes to your apps data model and how it tracks and manages files. Depending on your app, it might also require changes to your apps user interface and overall configuration. And if you want to share files between iOS and Mac OS X devices, it might require changing how you construct your file formats too. Important: Access to iCloud is controlled using entitlements, which your app configures through Xcode. If these entitlements are not present, your app is prevented from accessing files and other data in iCloud. For information about how to configure your apps iCloud entitlements, see Configuring Your Apps iCloud Entitlements (page 63).
61
CHAPTER 4
iCloud Storage
Document Storage
Doc
iCloud
Table 4-1 highlights some of the key usage patterns surrounding iCloud storage and how those patterns differ for document storage and key-value storage. Use this table to help answer some of your basic questions. Table 4-1 Attribute What kind of data can it manage? When would you use it? Differences between document and key-value storage Document storage Files and directories Key-value storage
Use document storage to manage data that is critical to your app. You almost always use document storage to manage files and data related directly to your apps main data model. Thus, you would use document storage for user documents, private app data files, and any files containing app or user-generated data.
Use key-value storage for things like p configuration data that you want to s of your app but that is not critical to y amount of space in the key-value store of data you can store are limited to pr No
Are file Yes presenters and file coordinators required? How do you locate data? How do you manage the data? How much data can it store? Use a NSMetadataQuery object to search for files.
Use the default NSUbiquitousKeyVa retrieve the value for a known key.
Manage files and directores using the NSFileManager class. Open, Set or get keys and values using the d NSUbiquitousKeyValueStore obje close, read, and write files using standard file system routines.
Limited only by the amount of space in the users iCloud account. Limited to a maximum of 64 KB (with of 64 KB).
62
CHAPTER 4
iCloud Storage
Attribute How are conflicts handled? What entitlement is required to use it?
Document storage Your apps file presenters must resolve conflicts manually.
Key-value storage
The last value set for the key is always timestamp provided by the device is u newest value.
com.apple.developer.ubiquity-container-identifiers com.apple.developer.ubiquity-
When is data iCloud always pulls file metadata and data from a device when synchronized? changes occur. Devices always pull file metadata but usually do not pull changed data until your app attempts to use the file. How do you detect if iCloud is available at launch time?
Call the URLForUbiquityContainerIdentifier: method for Call the synchronize method of the one of your registered container directories. If the method returns ValueStore object. If that method re nil, document storage is not available. available and there are changes to syn user defaults database. If that method either not available or there are no ch Either way, use the values in your loca
None. Your app is responsible for deciding what information (if None. In most cases, you should not n any) to convey about iCloud support. In general, iCloud information key-value data is stored locally or in iC should be conveyed seamlessly and involve minimal changes to your user interface.
Another design consideration is how you plan to incorporate iCloud support into your apps user interface. Especially for documents, there may be times when you need to inform the user about the state of a document, such as whether it is downloaded or has version conflicts that need to be resolved. In those situations, you should consider adding some unobtrusive elements to your user interface to convey the appropriate information to the user. For more information about updating your user interface, see Updating Your User Interface for iCloud (page 70).
63
CHAPTER 4
iCloud Storage
When you enable entitlements for your app target, Xcode automatically configures both the document storage and and key-value data storage entitlements for your app. Each entitlement consists of an entitlement key whose value is one or more container identifier strings. A container identifier string identifies one of the iCloud container directories you use to store your apps files. Xcode configures the entitlements in the following way:
The iCloud Containers field identifies the list of container directories that your app can access in the users iCloud storage. (This field corresponds to the com.apple.developer.ubiquity-container-identifiers entitlement.) The strings you add to this list must correspond to bundle identifiers for apps created by your team. Xcode uses the current apps bundle identifier to specify the first string; you can change this to a different bundle identifier if you want multiple apps to share a main container directory. You can also add additional bundle identifiers for your teams other apps. (The first string must not contain any wildcard characters but subsequent strings may if you do not want to specify every bundle identifier separately.) The iCloud Key-Value Store field contains the single container identifier string corresponding to the iCloud key-value data storage for your app. (This field corresponds to the com.apple.developer.ubiquity-kvstore-identifier entitlement.)
The bundle identifiers you specify in Xcode do not represent the fully qualified container identifier strings that are written to your entitlements file. A fully qualified container identifier is of the form <TEAM_ID>.<BUNDLE_IDENTIFIER>, where <TEAM_ID> is the unique ten-character identifier associated with your development team and <BUNDLE_IDENTIFIER> is is one of the bundle identifiers in the iCloud Containers field. When retrieving a URL for a container directory in your code, you need to pass the fully qualified string to the URLForUbiquityContainerIdentifier: method. However, you can also pass nil to this method to retrieve the URL for the first container directory in the list. Note: You can find the unique <TEAM_ID> value for your development team in the Member Center on the Apple Developer website (http://developer.apple.com/membercenter). From the Member Center home page, select the Your Account tab and then select Organization Profile from the column on the left of that tab. Your teams identifier is in the Company/Organization ID field. Apps using iCloud document storage can read and write the contents of multiple container directories by specifying multiple container identifiers in their entitlements file. The iCloud Containers field lets you specify multiple strings. The first string in this field must always be the main container identifier for your app. Any additional strings represent the container identifiers for your other apps. Searches return a merged set of files from all of the available container directories. For more information about how to configure entitlements for an iOS app, see Configuring Applications in iOS App Development Workflow Guide.
64
CHAPTER 4
iCloud Storage
Figure 4-1
File
Local storage
Local storage
File
File
Designing your app to take advantage of iCloud document storage requires some significant changes. Here are the main changes needed:
Early in your apps execution, call the URLForUbiquityContainerIdentifier: method to determine if iCloud is enabled. Calling this method is also necessary to extend your app sandbox to include each of your apps requested container directories; see Determining if iCloud Document Storage is Available (page 66). Explicitly incorporate file presenters (such as the UIDocument class) into your data layer; see Incorporating File Presenters into Your Workflow (page 66). Explicitly move files to iCloud; see Manipulating Files and Directories in iCloud (page 66). Be prepared to handle version conflicts for a file; see Choosing a Strategy to Respond to Version Conflicts (page 67). Make use of searches to locate files in iCloud; see Incorporating Search into Your Infrastructure (page 68). Be prepared to handle cases where files are in iCloud but not fully downloaded to the local device; this might require providing the user with feedback; see Determining the Transfer Status of a File or Directory (page 69). Use Core Data if you want to store live databases in iCloud; do not use SQLite. If you also have a Mac OS X version of your app, use a common document format for both apps.
65
CHAPTER 4
iCloud Storage
Most of the work you do to support iCloud happens in the data layer of your app. Interactions with iCloud occur mostly through the files and directories that your app uses to store data. But you also need to consider the implications that the underlying data changes have on your apps user interface. Wherever possible, the user should not have to care whether a file is stored locally or in iCloud. The exceptions are in cases where the user experience might be degraded.
66
CHAPTER 4
iCloud Storage
To move a file or directory to iCloud: 1. Create the file or directory locally in your app sandbox. While in use, the file or directory must be managed by a file presenter, such as a UIDocument object. 2. Use the URLForUbiquityContainerIdentifier: method to retrieve a URL for the iCloud container directory in which you want to store the item. Use the container directory URL to build a new URL that specifies the items location in iCloud. Call the setUbiquitous:itemAtURL:destinationURL:error: method of NSFileManager to move the item to iCloud. Never call this method from your apps main thread; doing so could block your main thread for an extended period of time or cause a deadlock with one of your apps own file presenters.
3. 4.
When you move a file or directory to iCloud, the system copies that item out of your app sandbox and into a private local directory so that it can be monitored by the iCloud daemon. Even though the file is no longer in your sandbox, your app still has full access to it. Although a copy of the file remains local to the current device, the file is also sent to iCloud so that it can be distributed to other devices. The iCloud daemon handles all of the work of making sure that the local copies are the same. So from the perspective of your app, the file just is in iCloud. All changes you make to a file or directory in iCloud must be made using a file coordinator object. These changes include moving, deleting, copying, or renaming the item. The file coordinator ensures that the iCloud daemon does not change the file or directory at the same time and ensures that other interested parties are notified of the changes you make. Note: When naming files and directories, use the alphanumeric character set as much as possible and avoid special punctuation or other special characters. You should also assume that filenames are case insensitive. Keeping your filenames simple helps ensure that those files can be handled correctly on different types of file systems. For more information about how to manipulate files and directories, see File System Programming Guide.
67
CHAPTER 4
iCloud Storage
3.
For each file version object, perform whatever actions are needed to resolve the conflict. For example:
Merge the changed data from the conflicting files, if it is practical to do so. Ignore one of the conflicting versions, if you can do so safely or without losing any data. Prompt the user to select which version of the file (current or conflict) to keep. This should always be the last option.
4.
If the current file remains the winner, you do not need to update the current file. If a conflict version is chosen as the winner, use a coordinated write operation to overwrite the contents of the current file with the contents of the conflict version. If the user chooses to save the conflict version under a different name, create the new file with the contents of the conflict version.
5.
Set the resolved property of the conflict version objects to YES. Setting this property to YES causes the conflict version objects (and their corresponding files) to be removed from the users iCloud storage.
Detecting conflicts depends on whether your app uses UIDocument or implements custom file presenters. If your app uses the UIDocument class, you detect states by monitoring the value of the documentState property and observing the related state change notification. If you implement custom file presenters, whenever a new version is reported, you should check to see whether it is a conflict version. For more information about handling conflicts in UIDocument objects, see Document-Based Application Programming Guide for iOS. For information about responding to conflicts in custom file presenters, see File System Programming Guide.
68
CHAPTER 4
iCloud Storage
Important: Metadata queries return results only when iCloud is enabled and the corresponding container directories have been created. At launch time, use the URLForUbiquityContainerIdentifier: method to determine if iCloud is enabled and your apps supported container directories are available. That method also creates the corresponding directory if it does not yet exist. Metadata queries search all of the container directories listed in your apps com.apple.developer.ubiquity-container-identifiers entitlement and return a merged set of results. If you want the contents of a single container directory, you can alternatively use the URLForUbiquityContainerIdentifier: method to get the URL for that directory and obtain a static list of its contents using the NSFileManager class. For information about how to create and configure metadata search queries, see File Metadata Search Programming Guide. For information about how to iterate directories using NSFileManager, see File System Programming Guide.
percentage of the changes have already been downloaded. You can use this value to update progress bars. NSURLUbiquitousItemIsUploadedKeyIndicates that locally made changes were successfully uploaded to the iCloud server. NSURLUbiquitousItemIsUploadingKeyIndicates that locally made changes are being uploaded to the iCloud server now. NSURLUbiquitousItemPercentUploadedKeyFor an item being uploaded, indicates what percentage of the changes have already been uploaded to the server. Although the iCloud server aggressively pulls changes your app makes locally, iOS devices typically do not pull changes from the server until you try to access the file. If you try to open a file that is currently being downloaded, iOS blocks the thread that issued the open request until the file is downloaded and available for use. Thus, if you are concerned about potential delays, check the files current state as needed and possibly update your user interface to reflect that the file is not yet available or is currently downloading. For more information about the attributes you can request for URLs, see NSURL Class Reference.
69
CHAPTER 4
iCloud Storage
Your app attempts to open or access the file. Your app calls the startDownloadingUbiquitousItemAtURL:error: method to download the changes explicitly.
If your app opens a file that is not yet downloaded, the file coordinator used to open the file blocks your app until the file or its changes have been downloaded. Depending on the size of the changes, this might not lead to the best user experience, so it is preferable to check the download status of a file before trying to open it. The NSURL class defines properties related to iCloud items, including whether the file is stored in iCloud and whether it is currently downloaded. To obtain the value for one of these keys, use the getResourceValue:forKey:error: method of NSURL. For example, to determine whether a file was downloaded, you could use code similar to the following:
- (BOOL)downloadFileIfNotAvailable:(NSURL*)file { NSNumber* isIniCloud = nil; if ([file getResourceValue:&isIniCloud forKey:NSURLIsUbiquitousItemKey error:nil]) { // If the item is in iCloud, see if it is downloaded. if ([isIniCloud boolValue]) { NSNumber* isDownloaded = nil; if ([file getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil]) { if ([isDownloaded boolValue]) return YES; // Download the file. NSFileManager* fm = [NSFileManager defaultManager]; [fm startDownloadingUbiquitousItemAtURL:file error:nil]; return NO; } } } // Return YES as long as an explicit download was not started. return YES; }
For more information about the iCloud-related properties available for your URLs, see NSURL Class Reference.
70
CHAPTER 4
iCloud Storage
When a user-generated document must be downloaded before it can be used. Giving the user control over whether to download a document is needed only if your app presents some sort of document browser. For files your app manages privately, download them automatically if they are not available. Any indicators you use should be subtle and provide the user with the option to begin downloading the document. If a download might take more than a few seconds, you might also want to display the current download progress. When there is a version conflict that the user must resolve. Version conflicts can occur when the same document is modified on two different devices at the same time. (This can occur if one of the devices was not connected to the network when the changes were made.) If your app needs user assistance to resolve the conflict, present a subtle indicator that this is the case. Do not display an alert or any sort of disruptive interface to notify the user that a conflict exists. When you want to give the user the option to enable or disable iCloud usage entirely for your app. If your app includes a Settings bundle or inline preferences, you could include a preference to toggle whether your app stores content in iCloud at all. For example, an app whose data consists entirely of privately managed files might do this to give the user the choice of how those files are stored.
For tips and guidance about how to design your apps user interface, see iOS Human Interface Guidelines.
71
CHAPTER 4
iCloud Storage
override the managedObjectModel property of the class to customize the object models for a given subclass.) Because most of your data is handled by a managed object context, this means that you can often use the UIManagedDocument class without subclassing. Behaviors such as saving are handled automatically thanks to the inherited autosave behavior provided for all documents. When creating new documents, do the following: 1. 2. Create your instance of the UIManagedDocument class. Add the NSPersistentStoreUbiquitousContentNameKey key to the dictionary in your documents persistentStoreOptions property. The value of this key is a unique name that your app can use to identify the document. Add some initial data to the document. Save the document to disk using the saveToURL:forSaveOperation:completionHandler: method. When saving a document, you can either save it directly to iCloud or you can save it to a local directory and move it to iCloud later. To save the document directly to iCloud, specify a URL that is based on a location returned by the URLForUbiquityContainerIdentifier: method. If you save the document locally, you can move it to iCloud later using the setUbiquitous:itemAtURL:destinationURL:error: method. When you create a new document, Core Data creates a file package containing the document contents. Among these contents are a DocumentMetadata.plist file and a directory containing the SQLite data store. Everything in the file package is transferred to the iCloud server except for the SQLite data store, which remains local to the device. When opening existing documents that reside in iCloud, do the following: 1. Use an NSMetadataQuery object to search for documents in iCloud. Metadata queries identify all of your Core Data documents, regardless of whether they were created locally or on another device. For documents created on other devices, the only thing present in the documents file package initially is the DocumentMetadata.plist file. 2. Open the DocumentMetadata.plist file and retrieve the value of the NSPersistentStoreUbiquitousContentNameKey key. Create your instance of the UIManagedDocument class. Add the NSPersistentStoreUbiquitousContentNameKey key to the dictionary in your documents persistentStoreOptions property. The value of this key should match the value you retrieve from the DocumentMetadata.plist file. Call the openWithCompletionHandler: method of the document to open it.
3. 4.
3. 4.
5.
The first time your app opens a Core Data document that was created on another device, Core Data automatically detects the absence of the SQLite store and creates it locally. It then uses the value of the NSPersistentStoreUbiquitousContentNameKey key (that you added to the documents NSPersistentStoreUbiquitousContentNameKey property) to retrieve the appropriate transaction logs and rebuild the contents of the database. From that point on, you can make changes to the document and save them back to iCloud. The changes you make are stored in a new log file so that they can be incorporated into the SQLite stores on other devices.
72
CHAPTER 4
iCloud Storage
When changes for a document are received from iCloud, Core Data automatically folds them into that documents SQLite store and sends your app a NSPersistentStoreDidImportUbiquitousContentChangesNotification notification. Apps should always register for this notification and use it to refresh any affected records. If your app does not refresh its local copy of the data, it could save old changes back out to iCloud and create a conflict that would need to be resolved. By incorporating changes when they arrive, your app should be able to avoid such conflicts. When you want to delete a document, you must delete both the file package for the document and the directory containing the documents transaction logs. Deleting both of these items requires you to perform a coordinated write operation using an NSFileCoordinator object. The DocumentMetadata.plist file of your document contains a NSPersistentStoreUbiquitousContentURLKey key with the URL of the transaction logs directory for your document. For more information on using file coordinators, see File System Programming Guide. For information on how to use Core Data stores to manage the objects in your app, see Core Data Programming Guide.
2.
Because you have only one data store, you can use whatever name you want for the NSPersistentStoreUbiquitousContentNameKey key. For the NSPersistentStoreUbiquitousContentURLKey key, the URL you provide should be a directory located in one of your iCloud container directories. In other words, the URL should be based on a location returned by the URLForUbiquityContainerIdentifier: method. Core Data writes changes to the directory you specify and looks in that directory for changes from other devices. When it detects the changes, it incorporates them into the local SQLite store and notifies your application. You should always respond to iCloud-related change notifications. These notifications are a way for you to make sure your app is using the updated values. If you continue to use an older version of the data, you could overwrite the newer data or create a version conflict that would need to be resolved later. For information on how to create a Core Data store, see Core Data Programming Guide.
73
CHAPTER 4
iCloud Storage
74
CHAPTER 4
iCloud Storage
The NSUbiquitousKeyValueStore class must not be used as a replacement for the NSUserDefaults class. An app should always write all of its configuration data to disk using the NSUserDefaults class, too. It should then write the data it intends to share to the key-value data store using the NSUbiquitousKeyValueStore class. This ensures that if iCloud is not available, you still have access to the configuration data you need. For more information about how to use the key-value store in your app, see Preferences and Settings Programming Guide.
Have a good strategy for storing iCloud documents. Whenever possible, give the user a single option to store all data in iCloud. Deleting a document removes it from a users iCloud account and from all of that users computers and devices. Make sure that users are aware of this fact and confirm any delete operations. If you want to refresh the local copy of a document, use the evictUbiquitousItemAtURL:error: method of NSFileManager instead of deleting the file. When storing documents in iCloud, place them in the Documents subdirectory whenever possible. Documents inside a Documents directory can be deleted individually by the user to free up space. However, everything outside that directory is treated as data and must be deleted all at once. Never store caches or other files that are private to your app in a users iCloud storage. A users iCloud account should be used only for storing user-related data and content that cannot be re-created by your app. Treat files in iCloud the same way you treat all other files in your app sandbox. The time at which to save a file should be driven by the need of your app and the need to preserve the users data. You should not change your app to save files more or less frequently for iCloud. iCloud automatically optimizes its transfers to the server to ensure the best possible performance.
75
CHAPTER 4
iCloud Storage
76
CHAPTER 5
App-Related Resources
Aside from the images and media files your app presents on screen, there are some specific resources that iOS itself requires your app to provide. The system uses these resources to determine how to present your app on the users home screen and, in some cases, how to facilitate interactions with other parts of the system.
Your app must have an Info.plist file. This file contains information that the system needs to interact with your app. Xcode creates a version of this file automatically but most apps need to modify this file in some way. For information on how to configure this file, see The Information Property List File (page 77). Your apps Info.plist file must include the UIRequiredDeviceCapabilities key. The App Store uses this key to determine whether or not a user can run your app on a specific device. For information on how to configure this key, see Declaring the Required Device Capabilities (page 78). Your app must include one or more icons to use when displaying the app. Your icon is what is presented to the user on the iOS devices home screen. For information about how to specify app icons, see App Icons (page 81). Your app must include at least one image to be displayed while your app is launching. The system displays your apps launch image after launch to provide the user with immediate feedback. For information about launch images, see App Launch (Default) Images (page 83).
UIRequiredDeviceCapabilitiesThe App Store uses this key to determine the capabilities of your
app and to prevent it from being installed on devices that do not support features your app requires. For more information about this key, seeDeclaring the Required Device Capabilities (page 78).
77
CHAPTER 5
App-Related Resources
CFBundleIconsThis is the preferred key for specifying your apps icon files. Older projects might include the CFBundleIconFiles key instead. Both keys have essentially the same purpose but the CFBundleIcons key is preferred because it allows you to organize your icons more efficiently. (The CFBundleIcons key is also required for Newsstand apps.) UISupportedIntefaceOrientationsThis key is included by Xcode and is set to an appropriate
set of values initially. However, you should add or remove values based on the orientations that your app actually supports. You might also want to include the following keys in your apps Info.plist file, depending on the behavior of your app:
UIBackgroundModesInclude this key if your app supports executing in the background using one
of the defined modes; see Implementing Long-Running Background Tasks (page 54).
UIFileSharingEnabledInclude this key if you want to expose the contents of your sandboxs Documents directory in iTunes. UIRequiresPersistentWiFiInclude this key if your app requires a Wi-Fi connection. UINewsstandAppInclude this key if your app presents content from the Newsstand app.
The Info.plist file itself is a property list file that you can edit manually or using Xcode. Each new Xcode project contains a file called <project_name>-Info.plist, where <project_name> is the name of your Xcode project. This file is the template that Xcode uses to generate an Info.plist file at build time. When you select this file, Xcode displays the property list editor that you can use to add or remove keys or change the value of a key. For information about how to configure the contents of this file, see Property List Editor Help. For details about the keys you can include in the Info.plist file, see Information Property List Key Reference.
78
CHAPTER 5
App-Related Resources
Table 5-1 lists the keys that you can include in the array or dictionary for the UIRequiredDeviceCapabilities key. You should include keys only for the features that your app absolutely requires. If your app can do without a specific feature, do not include the corresponding key. Table 5-1 Key
accelerometer
Dictionary keys for the UIRequiredDeviceCapabilities key Description Include this key if your app requires (or specifically prohibits) the presence of accelerometers on the device. Apps use the Core Motion framework to receive accelerometer events. You do not need to include this key if your app detects only device orientation changes. Include this key if your app is compiled only for the armv6 instruction set. (iOS 3.1 and later) Include this key if your app is compiled only for the armv7 instruction set. (iOS 3.1 and later) Include this key if your app requires (or specifically prohibits) autofocus capabilities in the devices still camera. Although most developers should not need to include this key, you might include it if your app supports macro photography or requires sharper images in order to perform some sort of image processing. Include this key if your app requires (or specifically prohibits) the presence of Bluetooth low-energy hardware on the device. (iOS 5 and later.) Include this key if your app requires (or specifically prohibits) the presence of a camera flash for taking pictures or shooting video. Apps use the UIImagePickerController interface to control the enabling of this feature.
armv6
armv7
auto-focus-camera
bluetooth-le
camera-flash
front-facing-camera Include this key if your app requires (or specifically prohibits) the presence of a forward-facing camera. Apps use the UIImagePickerController interface
Include this key if your app requires (or specifically prohibits) Game Center. (iOS 4.1 and later) Include this key if your app requires (or specifically prohibits) the presence of GPS (or AGPS) hardware when tracking locations. (You should include this key only if you need the higher accuracy offered by GPS hardware.) If you include this key, you should also include the location-services key. You should require GPS only if your app needs location data more accurate than the cellular or Wi-fi radios might otherwise provide. Include this key if your app requires (or specifically prohibits) the presence of a gyroscope on the device. Apps use the Core Motion framework to retrieve information from gyroscope hardware. Include this key if your app requires (or specifically prohibits) the ability to retrieve the devices current location using the Core Location framework. (This key refers to the general location services feature. If you specifically need GPS-level accuracy, you should also include the gps key.)
gps
gyroscope
location-services
79
CHAPTER 5
App-Related Resources
Key
magnetometer
Description Include this key if your app requires (or specifically prohibits) the presence of magnetometer hardware. Apps use this hardware to receive heading-related events through the Core Location framework. Include this key if your app uses the built-in microphone or supports accessories that provide a microphone. Include this key if your app requires (or specifically prohibits) the presence of the OpenGL ES 1.1 interfaces. Include this key if your app requires (or specifically prohibits) the presence of the OpenGL ES 2.0 interfaces. Include this key if your app requires (or specifically prohibits) peer-to-peer connectivity over a Bluetooth network. (iOS 3.1 and later) Include this key if your app requires (or specifically prohibits) the presence of the Messages app. You might require this feature if your app opens URLs with the sms scheme. Include this key if your app requires (or specifically prohibits) the presence of a camera on the device. Apps use the UIImagePickerController interface to capture images from the devices still camera. Include this key if your app requires (or specifically prohibits) the presence of the Phone app. You might require this feature if your app opens URLs with the tel scheme. Include this key if your app requires (or specifically prohibits) the presence of a camera with video capabilities on the device. Apps use the UIImagePickerController interface to capture video from the devices camera. Include this key if your app requires (or specifically prohibits) access to the networking features of the device.
microphone
opengles-1
opengles-2
peer-peer
sms
still-camera
telephony
video-camera
wifi
For detailed information on how to create and edit property lists, see Information Property List Key Reference.
80
CHAPTER 5
App-Related Resources
In Xcode, you declare your document (file) types from the Info tab of your targets settings. In the Document Types section of this tab, you can add and delete supported document types and configure the types you have. A document type is your apps way of associating specific types of files with specific information about how your app handles that type of file. A single document type can represent one type of file or multiple types of files. For example, you can define a single document type that represents only PNG images or that represents PNG, JPG, and GIF images. The decision to represent one file type or multiple file types depends on how your app presents the files. If it presents all of the files in the same waythat is, with the same icon and with the same basic code paththen you can use one document type for multiple file types. If the code paths or icons for a given file type are different, you should declare different document types for each. For each document type, you must provide the following information at a minimum:
A name. This is a localizable string that can be displayed to the user if needed. An icon. All files associated with a document type share the same icon. The file types. These are uniform type identifier (UTI) strings that are used to identify the file types. For example, to specify the PNG file type, you would specify the public.png UTI. UTIs are the preferred way to specify file types because they are less fragile than filename extensions and other techniques used to identify files.
Although you use Xcode to configure your document types, the information you enter in Xcode is ultimately added to your apps Info.plist file as a collection of keys. Document types are declared using the CFBundleDocumentTypes key, which is an array of dictionaries. Each dictionary contains the keys that specify the document types name, icon, file types, and so on. In addition to the basic keys, there are other keys you can associate with your document types. For example, you would use one of these other keys to declare your document type as a file package, which is an opaque directory that is treated by the system as if it were a single file. For more information on the keys you use to declare your apps document types, see Information Property List Key Reference.
App Icons
Every app must provide an icon to be displayed on a devices Home screen and in the App Store. An app may actually specify several different icons for use in different situations. For example, an app can provide a small icon to use when displaying search results and can provide a high-resolution icon for devices with Retina displays. To specify the icons for your app, add the CFBundleIconFiles key to your apps Info.plist file and add the filenames of your icon image to the associated array. The filenames can be anything you want, but all image files must be in the PNG format and reside in the top level of your app bundle. When the system needs an appropriately sized icon, it looks at the files in the CFBundleIconFiles array and picks the one whose size most closely matches the intended usage. (If your app runs in iOS 3.1.3 or earlier, you must use specific names for your icon image files; these filenames are described later in this section.) Table 5-2 lists the dimensions of the icons you can associate with the CFBundleIconFiles key, along with the intended usage for each one. For apps that run on devices with Retina displays, two versions of each icon should be provided, with the second one being a high-resolution version of the original. The names of
App Icons
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
81
CHAPTER 5
App-Related Resources
the two icons should be the same except for the inclusion of the string @2x in the filename of the high-resolution image. You can find out more about specifying and loading high-resolution image resources in Drawing and Printing Guide for iOS. For detailed information about the usage and preparation of your icons, see iOS Human Interface Guidelines. Table 5-2 Icon Sizes for images in the CFBundleIconFiles key Idiom Size 57 x 57 pixels 114 x 114 pixels (@2x) App icon (required) iPad Settings/Search results icon 72 x 72 pixels Usage This is the main icon for apps running on iPhone and iPod touch. The @2x variant of the icon is for use on devices with Retina displays only. This is the main icon for apps running on iPad. This is the icon displayed in conjunction with search results on iPhone and iPod touch. This icon is also used by the Settings app on all devices. (The @2x variant of the icon is for use on devices with Retina displays only and is not supported on iPad.) Search results icon iPad 50 x 50 pixels This is the icon displayed in conjunction with search results on iPad.
When specifying icon files using the CFBundleIconFiles key, it is best to omit the filename extensions of your image files. If you include a filename extension, you must explicitly add the names of all image files (including any high-resolution variants) to the array. When you omit the filename extension, the system automatically detects high-resolution variants of your file, even if they are not included in the array. Note: Do not confuse the CFBundleIconFiles key with the CFBundleIconFile key. The keys provide similar behaviors, but the plural version is preferred because it allows you to specify an array of image filenames instead of a single filename. The plural version of the key is supported only in iOS 3.2 and later. If your iPhone app is running in iOS 3.1.3 or earlier, the system does not look for the CFBundleIconFiles key. Instead, it looks for icon files with specific names. The CFBundleIconFiles key was introduced in iOS 3.2 and is not recognized by earlier versions of the system. Although the sizes of the icons are the same as those in Table 5-2 (page 82), if your app supports deployment on iOS 3.1.3 and earlier, you must use the following filenames when naming your icons:
Icon.png. The name for the app icon on iPhone or iPod touch. Icon-72.png. The name for the app icon on iPad. Icon-Small.png. The name for the search results icon on iPhone and iPod touch. This file is also used
82
App Icons
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
CHAPTER 5
App-Related Resources
Important: The use of fixed filenames for your app icons is for compatibility with earlier versions of iOS only. Even if you use these fixed icon filenames, your app should continue to include the CFBundleIconFiles key in its Info.plist if it is able to run in iOS 3.2 and later. In iOS 3.2 and earlier, the system looks for icons with the fixed filenames first. In iOS 4 and later, the system looks for icons in the CFBundleIconFiles key first. Developers who distribute their apps using ad hoc distribution must include a 512 x 512 version of their icon and give it the name iTunesArtwork (no filename extension). This icon is displayed by iTunes when presenting your app for distribution. Like all other icon files, the iTunesArtwork image file must reside at the top level of your app bundle. The file should be the same one you submit to the App Store (typically, a JPEG or PNG file) if you were distributing your app that way. For more information about the CFBundleIconFiles key, see Information Property List Key Reference. For information about creating your app icons, see iOS Human Interface Guidelines.
iPhone and iPod touch 320 x 480 pixels 640 x 960 pixels (high resolution) iPad 768 x 1004 pixels
83
CHAPTER 5
App-Related Resources
To demonstrate the naming conventions, suppose your iOS apps Info.plist file included the UILaunchImageFile key with the value MyLaunchImage. The standard resolution version of the launch image would be named MyLaunchImage.png and would be in a portrait orientation (320 x 480). The high-resolution version of the same launch image would be named [email protected]. If you did not specify a custom launch image name, these files would need to be named Default.png and [email protected], respectively. For more information about the UILaunchImageFile key, see Information Property List Key Reference.
-PortraitUpsideDown Specifies an upside-down portrait version of the launch image. A file with this modifier takes precedence over a file with the -Portrait modifier for this
specific orientation.
-LandscapeLeft
Specifies a left-oriented landscape version of the launch image. A file with this modifier takes precedence over a file with the -Landscape modifier for this specific orientation. Specifies a right-oriented landscape version of the launch image. A file with this modifier takes precedence over a file with the -Landscape modifier for this specific orientation. Specifies the generic portrait version of the launch image. This image is used for right-side up portrait orientations and takes precedence over the Default.png image file (or your custom-named replacement for that file). If a file with the -PortraitUpsideDown modifier is not specified, this file is also used for upside-down portrait orientations as well. Specifies the generic landscape version of the launch image. If a file with the -LandscapeLeft or -LandscapeRight modifier is not specified, this image is used instead. This image takes precedence over the Default.png image file (or your custom-named replacement for that file). If you provide a launch image file with no orientation modifier, that file is used when no other orientation-specific launch image is available. For apps running on systems earlier than iOS 3.2, you must name this file Default.png.
-LandscapeRight
-Portrait
-Landscape
(none)
84
CHAPTER 5
App-Related Resources
For example, if you specify the value MyLaunchImage in the UILaunchImageFile key, the custom landscape and portrait launch images for your iPad app would be named MyLaunchImage-Landscape.png and MyLaunchImage-Portrait.png. If you do not specify a custom launch image filename, you would use the names Default-Landscape.png and Default-Portrait.png. No matter which launch image is displayed by the system, your app always launches in a portrait orientation initially and then rotates as needed to the correct orientation. Therefore, your application:didFinishLaunchingWithOptions: method should always assume a portrait orientation when setting up your window and views. Shortly after the application:didFinishLaunchingWithOptions: method returns, the system sends any necessary orientation-change notifications to your apps window, giving it and your apps view controllers a chance to reorient views using the standard process. For more information about how your view controllers manage the rotation process, see Custom View Controllers in View Controller Programming Guide for iOS.
~ipad. The launch image should be loaded on iPad devices only. ~iphone. The launch image should be loaded on iPhone or iPod touch devices only.
Because device modifiers are not supported in iOS 3.2, the minimal set of launch images needed for a universal app (running in iOS 3.2 and later) would need to be named Default.png and Default~iphone.png. In that case, the Default.png file would contain the iPad launch image (for all orientations) and the Default~iphone.png file would contain the iPhone version of the image. (To support high-resolution displays, you would also need to include a Default@2x~iphone.png launch image.) Note: If you are using the UILaunchImageFile key in your Info.plist file to specify a custom base name for your launch image files, add device-specific versions as needed to differentiate the launch images on different devices. For example, specify a UILaunchImageFile~ipad key to specify a different base name for iPad launch images. Specifying different base names lets a universal app avoid naming conflicts among its launch images. For more information on how to apply device modifiers to keys in the Info.plist file, see Information Property List Key Reference.
85
CHAPTER 5
App-Related Resources
The <url_scheme> modifier is a string representing the name of your URL scheme name. For example, if your app supports a URL scheme with the name myscheme, the system looks for an image with the name Default-myscheme.png (or [email protected] for Retina displays) in the apps bundle. If the apps Info.plist file includes the UILaunchImageFile key, the base name portion changes from Default to the custom string you provide in that key. Note: You can combine a URL scheme modifier with orientation modifiers. If you do this, the format for the filename is <basename>-<url_scheme><orientation_modifier><scale_modifier><device_modifier>.png. For more information about the launch orientation modifiers, see Protecting Data Using On-Disk Encryption (page 94). In addition to including the launch images at the top level of your bundle, you can also include localized versions of your launch images in your apps language-specific project subdirectories. For more information on localizing resources in your app, see Table 6-2 (page 99).
86
CHAPTER 5
App-Related Resources
Note: Because changing preferences in the Settings app requires leaving your app, you should use a Settings bundle only for preferences that the user changes infrequently. Frequently changed settings should be included directly inside your app. Xcode provides support for creating a Settings bundle resource and adding it to your app. Inside the Settings bundle, you place one or more property list files and any images associated with your preferences. Each property-list file contains special keys and values that tell the Settings app how to display different pages of your preferences. Changes to your apps preferences are stored in the user defaults database and are accessible to your app using an NSUserDefaults object. For detailed information about how to create a Settings bundle, see Preferences and Settings Programming Guide.
Storyboard files (or nib files)Storyboards can contain text labels and other content that need to be localized. You might also want to adjust the position of interface items to accommodate changes in text length. (Similarly, nib files can contain text that needs to be localized or layout that needs to be updated.) Strings filesStrings files (so named because of their .strings filename extension) contain localized text that you plan to display in your app. Image filesYou should avoid localizing images unless the images contain culture-specific content. And you should never store text directly in your image files. Instead, store text in a strings file and composite that text with your image-based content at runtime.. Video and audio filesYou should avoid localizing multimedia files unless they contain language-specific or culture-specific content. For example, you would want to localize a video file that contained a voice-over track.
For information about the internationalization and localization process, see Internationalization Programming Topics. For information about the proper way to use resource files in your app, see Resource Programming Guide.
87
CHAPTER 5
App-Related Resources
88
CHAPTER 6
Many app-related tasks depend on the type of app you are trying to create. This chapter shows you how to implement some of the common behaviors found in iOS apps.
iphoneThe key applies to iPhone devices. ipodThe key applies to iPod touch devices. ipadThe key applies to iPad devices.
89
CHAPTER 6
For example, to indicate that you want your app to launch in a portrait orientation on iPhone and iPod touch devices but in landscape-right on iPad, you would configure your Info.plist with the following keys:
<key>UIInterfaceOrientation</key> <string>UIInterfaceOrientationPortrait</string> <key>UIInterfaceOrientation~ipad</key> <string>UIInterfaceOrientationLandscapeRight</string>
Notice that in the preceding example, there is an iPad-specific key and a default key without any device modifiers. Continue to use the default key to specify the most common (or default) value and add a specific version with a device-specific modifier when you need to change that value. This guarantees that there is always a value available for the system to examine. For example, if you were to replace the default key with an iPhone-specific and iPad-specific version of the UIInterfaceOrientation key, the system would not know the preferred starting orientation for iPod devices. For more information about the keys you can include in your Info.plist file, see Information Property List Key Reference
Consider defining separate view controller classes for iPhone and iPad devices. Using separate view controllers is often easier than trying to create one view controller that supports both platforms. If there is a significant amount of shared code, you could always put the shared code in a base class and then implement custom subclasses to address device-specific issues. If you use a single view controller class for both platforms, your code must support both iPhone and iPad screen sizes. (For an app that uses nib files, this might mean choosing which nib file to load based on the current device idiom.) Similarly, your view controller code must be able to handle differences between the two platforms.
Consider using separate sets of views for iPhone and iPad devices. For custom views, this means defining different versions of your class for each device. If you choose to use the same custom view for both devices, make sure your drawRect: and layoutSubviews methods especially work properly on both devices.
For information about the view controllers you can use in your apps, see View Controller Programming Guide for iOS.
90
CHAPTER 6
Apps that link against iOS SDK 4.2 and later can use the weak linking support introduced in that version of the SDK. This support lets you check for the existence of a given Class object to determine whether you can use that class. For example:
if ([UIPrintInteractionController class]) { // Create an instance of the class and use it. } else { // The print interaction controller is not available. }
To use this feature, you must build your app using LLVM and Clang and the apps deployment target must be set to iOS 3.1 or later.
Apps that link against iOS SDK 4.1 and earlier must use the NSClassFromString function to see whether a class is defined. If the function returns a value other than nil, you may use the class. For example:
Class splitVCClass = NSClassFromString(@"UISplitViewController"); if (splitVCClass) { UISplitViewController* mySplitViewController = [[splitVCClass alloc] init]; // Configure the split view controller. }
To determine whether a method is available on an existing class, use the instancesRespondToSelector: class method. To determine whether a C-based function is available, perform a Boolean comparison of the function name to NULL. If the result is YES, you can use the function. For example:
if (UIGraphicsBeginPDFPage != NULL) { UIGraphicsBeginPDFPage(); }
For more information and examples of how to write code that supports multiple deployment targets, see SDK Compatibility Guide.
91
CHAPTER 6
and later, apps that support earlier versions of iOS need to check for the availability of this property before accessing it. Of course, the simplest way to check this property is to use the UI_USER_INTERFACE_IDIOM macro, which performs the necessary runtime checks for you.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { // The device is an iPad running iOS 3.2 or later. } else { // The device is an iPhone or iPod touch. }
In addition to the Default.png file displayed when your app launches on iPhone devices, you must add new launch images for iPad devices as described in Providing Launch Images for Different Orientations (page 84). If you use images, you may need to add larger (or higher-resolution) versions to support iPad devices. If you use nib files, you need to provide a new set of nib files for iPad devices. You must size your app icons appropriately for iPad, as described in App Icons (page 81).
When using different resource files for each platform, you can conditionally load those resources just as you would conditionally execute code. For more information about how to use runtime checks, see Using Runtime Checks to Create Conditional Code Paths (page 91).
The currently visible view controller The structural arrangement of your view controllers Information about each view controller, including the class name of the view controller, which you use to recreate the view controller during the next launch cycle, and references to the data being managed by the view controller.
92
CHAPTER 6
One approach to saving this information is to build a property list that is structured to match the organization of your view controllers. In this property list, you save information about each view controller in a dictionary object. The keys of the dictionary identify properties of the view controller, such as its class name and pointers to any relevant data objects. For container view controllers, such as navigation and tab bar controllers, the dictionary should also contain an array with the dictionaries for any child view controllers. Practically speaking, your app should save information only about those view controllers that are not part of your apps default user interface. That is, when an app launches, it normally loads a main nib file or creates an initial set of views and view controllers. This initial set of view controllers provides the interface that users see when they first launch the app. Because these objects are always created, you may not need to save them in your property list. When your apps applicationDidEnterBackground: or applicationWillTerminate: method is called, build your property list and save it as an app preference. Then, in your application:didFinishLaunchingWithOptions: method, load the property list from preferences and use it to create and configure any additional view controllers you need.
Add the UIInterfaceOrientation key to your apps Info.plist file and set the value of this key to either UIInterfaceOrientationLandscapeLeft or UIInterfaceOrientationLandscapeRight. Lay out your views in landscape mode and make sure that their autoresizing options are set correctly. Override your view controllers shouldAutorotateToInterfaceOrientation: method and return YES for the left or right landscape orientations and NO for portrait orientations.
Important: Apps should always use view controllers to manage their window-based content. The UIInterfaceOrientation key in the Info.plist file tells iOS that it should configure the orientation of the app status bar (if one is displayed) as well as the orientation of views managed by any view controllers at launch time. In iOS 2.1 and later, view controllers respect this key and set their views initial orientation to match. Using this key is equivalent to calling the setStatusBarOrientation:animated: method of UIApplication early in the execution of your applicationDidFinishLaunching: method.
93
CHAPTER 6
Note: To launch a view controllerbased app in landscape mode in versions of iOS before 2.1, you need to apply a 90-degree rotation to the transform of the apps root view in addition to all the preceding steps.
The file system on the users device must support data protection. This is true for newer devices, but for some earlier devices, the user might have to reformat the devices disk and restore any content from a backup. The user must have an active passcode lock set for the device.
To protect a file, your app must add an extended attribute to the file indicating the level of desired protection. Add this attribute using either the NSData class or the NSFileManager class. When writing new files, you can use the writeToFile:options:error: method of NSData with the appropriate protection value as one of the write options. For existing files, you can use the setAttributes:ofItemAtPath:error: method of NSFileManager to set or change the value of the NSFileProtectionKey. When using these methods, your app can specify one of the following protection levels for the file:
No protectionThe file is not encrypted on disk. You can use this option to remove data protection from an accessible file. Specify the NSDataWritingFileProtectionNone option (NSData) or the NSFileProtectionNone attribute (NSFileManager).
94
CHAPTER 6
CompleteThe file is encrypted and inaccessible while the device is locked. Specify the NSDataWritingFileProtectionComplete option (NSData) or the NSFileProtectionComplete attribute (NSFileManager). Complete unless already openThe file is encrypted. A closed file is inaccessible while the device is locked. After the user unlocks the device, your app can open the file and continue to use it even if the user locks the device again. Specify the NSDataWritingFileProtectionCompleteUnlessOpen option (NSData) or the NSFileProtectionCompleteUnlessOpen attribute (NSFileManager). Complete until first loginThe file is encrypted and inaccessible until after the device has booted and the user has unlocked it once. Specify the NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication option (NSData) or the NSFileProtectionCompleteUntilFirstUserAuthentication attribute (NSFileManager).
If you protect a file, your app must be prepared to lose access to that file. When complete file protection is enabled, even your app loses the ability to read and write the files contents when the user locks the device. Your app has several options for tracking when access to protected files might change, though:
The app delegate can implement the applicationProtectedDataWillBecomeUnavailable: and applicationProtectedDataDidBecomeAvailable: methods. Any object can register for the UIApplicationProtectedDataWillBecomeUnavailable and UIApplicationProtectedDataDidBecomeAvailable notifications. Any object can check the value of the protectedDataAvailable property of the shared UIApplication object to determine whether files are currently accessible.
For new files, it is recommended that you enable data protection before writing any data to them. If you are using the writeToFile:options:error: method to write the contents of an NSData object to disk, this happens automatically. For existing files, adding data protection replaces an unprotected file with a new protected version.
2. 3.
95
CHAPTER 6
4. 5. 6.
Configure your audio session to handle transitions to and from active use. To ensure a better user experience on iPhone, use the Core Telephony framework to adjust your behavior in relation to cell-based phone calls; see Core Telephony Framework Reference. To ensure good performance for your VoIP app, use the System Configuration framework to detect network changes and allow your app to sleep as much as possible.
Including the voip value in the UIBackgroundModes key lets the system know that it should allow the app to run in the background as needed to manage its network sockets. This key also permits your app to play background audio (although including the audio value for the UIBackgroundModes key is still encouraged). An app with this key is also relaunched in the background immediately after system boot to ensure that the VoIP services are always available. For more information about the UIBackgroundModes key, see Information Property List Key Reference.
Configuring stream interfaces for VoIP usage Configuration For Cocoa streams, use the setProperty:forKey: method to add the NSStreamNetworkServiceType property to the stream. The value of this property should be set to NSStreamNetworkServiceTypeVoIP. When using the URL loading system, use the setNetworkServiceType: method of your NSMutableURLRequest object to set the network service type of the request. The service type should be set to NSURLNetworkServiceTypeVoIP. For Core Foundation streams, use the CFReadStreamSetProperty or CFWriteStreamSetProperty function to add the kCFStreamNetworkServiceType property to the stream. The value for this property should be set to kCFStreamNetworkServiceTypeVoIP.
NSURLRequest
96
CHAPTER 6
Note: When configuring your sockets, you need to configure only your main signaling channel with the appropriate service type key. You do not need to include this key when configuring your voice channels. Because VoIP apps need to stay running in order to receive incoming calls, the system automatically relaunches the app if it exits with a nonzero exit code. (This type of exit could happen when there is memory pressure and your app is terminated as a result.) However, terminating the app also releases all of its sockets, including the one used to maintain the VoIP service connection. Therefore, when the app is launched, it always needs to create its sockets from scratch. For more information about configuring Cocoa stream objects, see Stream Programming Guide for Cocoa. For information about using URL requests, see URL Loading System Programming Guide. And for information about configuring streams using the CFNetwork interfaces, see CFNetwork Programming Guide.
97
CHAPTER 6
3.
Adjusting your apps behavior based on the availability of the network can also help improve the battery life of the underlying device. Letting the system track the network changes means that your app can let itself go to sleep more often. For more information about the reachability interfaces, see System Configuration Framework Reference.
98
CHAPTER 6
If your app defines a custom URL scheme, it should implement a handler for that scheme as described in Implementing Custom URL Schemes (page 99). For more information about the system-supported URL schemes, including information about how to format the URLs, see Apple URL Scheme Reference.
Keys and values of the CFBundleURLTypes property Value A string containing the abstract name of the URL scheme. To ensure uniqueness, it is recommended that you specify a reverse-DNS style of identifier, for example, com.acme.myscheme. The string you specify is also used as a key in your apps InfoPlist.strings file. The value of the key is the human-readable scheme name.
CFBundleURLSchemes An array of strings containing the URL scheme namesfor example, http, mailto, tel, and sms.
Figure 6-1 shows the Info.plist file of an app that supports a custom scheme for creating to-do items. The URL types entry corresponds to the CFBundleURLTypes key added to the Info.plist file. Similarly, the URL identifier and URL Schemes entries correspond to the CFBundleURLName and CFBundleURLSchemes keys.
99
CHAPTER 6
Figure 6-1
Use the application:didFinishLaunchingWithOptions: method to retrieve information about the URL and decide whether you want to open it. This method is called only when your app is launched. In iOS 4.2 and later, use the application:openURL:sourceApplication:annotation: method to open the file. In iOS 4.1 and earlier, use the application:handleOpenURL: method to open the file.
If your app is not running when a URL request arrives, it is launched and moved to the foreground so that it can open the URL. The implementation of your application:didFinishLaunchingWithOptions: method should retrieve the URL from its options dictionary and determine whether the app can open it. If it can, return YES and let your application:openURL:sourceApplication:annotation: (or application:handleOpenURL:) method handle the actual opening of the URL. Figure 6-2 shows the modified launch sequence for an app that is asked to open a URL.
100
CHAPTER 6
Figure 6-2
Your code
UIApplicationMain()
Event Loop
Handle events
If your app is running but is in the background or suspended when a URL request arrives, it is moved to the foreground to open the URL. Shortly thereafter, the system calls the delegates application:openURL:sourceApplication:annotation: to check the URL and open it. If your delegate does not implement this method (or the current system version is iOS 4.1 or earlier), the system calls your delegates application:handleOpenURL: method instead. Figure 6-3 shows the modified process for moving an app to the foreground to open a URL.
101
CHAPTER 6
Figure 6-3
Event Loop
Handle events
Note: Apps that support custom URL schemes can specify different launch images to be displayed when launching the app to handle a URL. For more information about how to specify these launch images, see Providing Launch Images for Custom URL Schemes (page 85). All URLs are passed to your app in an NSURL object. It is up to you to define the format of the URL, but the NSURL class conforms to the RFC 1808 specification and therefore supports most URL formatting conventions. Specifically, the class includes methods that return the various parts of a URL as defined by RFC 1808, including the user, password, query, fragment, and parameter strings. The protocol for your custom scheme can use these URL parts for conveying various kinds of information. In the implementation of application:handleOpenURL: shown in Listing 6-1, the passed-in URL object conveys app-specific information in its query and fragment parts. The delegate extracts this informationin this case, the name of a to-do task and the date the task is dueand with it creates a model object of the app. This example assumes that the user is using a Gregorian calendar. If your app supports non-Gregorian calendars, you need to design your URL scheme accordingly and be prepared to handle those other calendar types in your code.
102
CHAPTER 6
Listing 6-1
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { if ([[url scheme] isEqualToString:@"todolist"]) { ToDoItem *item = [[ToDoItem alloc] init]; NSString *taskName = [url query]; if (!taskName || ![self isValidTaskString:taskName]) { // must have a task name [item release]; return NO; } taskName = [taskName stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; item.toDoTask = taskName; NSString *dateString = [url fragment]; if (!dateString || [dateString isEqualToString:@"today"]) { item.dateDue = [NSDate date]; } else { if (![self isValidDateString:dateString]) { [item release]; return NO; } // format: yyyymmddhhmm (24-hour clock) NSString *curStr = [dateString substringWithRange:NSMakeRange(0, 4)]; NSInteger yeardigit = [curStr integerValue]; curStr = [dateString substringWithRange:NSMakeRange(4, 2)]; NSInteger monthdigit = [curStr integerValue]; curStr = [dateString substringWithRange:NSMakeRange(6, 2)]; NSInteger daydigit = [curStr integerValue]; curStr = [dateString substringWithRange:NSMakeRange(8, 2)]; NSInteger hourdigit = [curStr integerValue]; curStr = [dateString substringWithRange:NSMakeRange(10, 2)]; NSInteger minutedigit = [curStr integerValue]; NSDateComponents *dateComps = [[NSDateComponents alloc] init]; [dateComps setYear:yeardigit]; [dateComps setMonth:monthdigit]; [dateComps setDay:daydigit]; [dateComps setHour:hourdigit]; [dateComps setMinute:minutedigit]; NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease]; NSDate *itemDate = [calendar dateFromComponents:dateComps]; if (!itemDate) { [dateComps release]; [item release]; return NO; } item.dateDue = itemDate; [dateComps release]; } [(NSMutableArray *)self.list addObject:item]; [item release]; return YES;
103
CHAPTER 6
} return NO; }
Be sure to validate the input you get from URLs passed to your app; see Validating Input And Interprocess Communication in Secure Coding Guide to find out how to avoid problems related to URL handling. To learn about URL schemes defined by Apple, see Apple URL Scheme Reference.
104
CHAPTER 7
Performance Tuning
At each step in the development of your app, you should consider the implications of your design choices on the overall performance of your app. The operating environment for iOS apps is more constrained than that for Mac OS X apps. The following sections describe the factors you should consider throughout the development process.
To prevent the syncing process from taking a long time, be selective about where you place files inside your apps home directory. Apps that store large files can slow down the process of backing up to iTunes or iCloud. These apps can also consume a large amount of a user's available storage, which may encourage the user to delete the app or disable backup of that app's data to iCloud. With this in mind, you should store app data according to the following guidelines:
Data that can be downloaded again or regenerated should be stored in the <Application_Home>/Library/Caches directory. Examples of files you should put in the Caches directory include (but are not limited to) database cache files and downloadable content, such as that used by magazine, newspaper, and map apps. Data that is used only temporarily should be stored in the <Application_Home>/tmp directory. Remember to delete those files when you are done with them so that they do not continue to consume space on the user's device.
105
CHAPTER 7
Performance Tuning
Documents and data that are user-generated or that cannot otherwise be recreated by your app, should be stored in the <Application_Home>/Documents directory
Although iTunes backs up the app bundle itself, it does not do this during every sync operation. Apps purchased directly from a device are backed up when that device is next synced with iTunes. Apps are not backed up during subsequent sync operations, though, unless the app bundle itself has changed (because the app was updated, for example). For additional guidance about how you should use the directories in your app, see File System Programming Guide.
<Application_Home>/Documents <Application_Home>/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
106
CHAPTER 7
Performance Tuning
Implement the applicationDidReceiveMemoryWarning: method of your app delegate. Override the didReceiveMemoryWarning method in your custom UIViewController subclass. Register to receive the UIApplicationDidReceiveMemoryWarningNotificationnotification.
Upon receiving any of these warnings, your handler method should respond by immediately freeing up any unneeded memory. For example, the default behavior of the UIViewController class is to purge its view if that view is not currently visible; subclasses can supplement the default behavior by purging additional data structures. An app that maintains a cache of images might respond by releasing any images that are not currently onscreen. If your data model includes known purgeable resources, you can have a corresponding manager object register for the UIApplicationDidReceiveMemoryWarningNotification notification and release its purgeable resources directly. Handling this notification directly avoids the need to route all memory warning calls through the app delegate. Note: You can test your apps behavior under low-memory conditions using the Simulate Memory Warning command in iOS Simulator.
Eliminate memory leaks. Because memory is a critical resource in iOS, your app should have no memory leaks. You can use the Instruments app to track down leaks in your code, both in Simulator and on actual devices. For more information on using Instruments, see Instruments User Guide. Make resource files as small as possible. Files reside on disk but must be loaded into memory before they can be used. Property list files and images can be made smaller with some very simple actions. To reduce the space used by property list files, write those files out in a binary format using the NSPropertyListSerialization class. For images, compress all image files to make them as small as possible. (To compress PNG imagesthe preferred image format for iOS appsuse the pngcrush tool.)
107
CHAPTER 7
Performance Tuning
Tip
Actions to take
Use Core Data or SQLite If your app manipulates large amounts of structured data, store it in a Core Data for large data sets. persistent store or in a SQLite database instead of in a flat file. Both Core Data and SQLite provides efficient ways to manage large data sets without requiring the entire set to be in memory all at once. The Core Data framework was introduced in iOS 3.0. Load resources lazily. You should never load a resource file until it is actually needed. Prefetching resource files may seem like a way to save time, but this practice actually slows down your app right away. In addition, if you end up not using the resource, loading it wastes memory for no good purpose.
Build your program Adding the -mthumb compiler flag can reduce the size of your code by up to using the Thumb option. 35%. However, if your app contains floating-pointintensive code modules and you are building your app for ARMv6, you should disable the Thumb option. If you are building your code for ARMv7, you should leave Thumb enabled.
Reduce your use of If your app does not use automatic reference counting (ARC) to manage its memory, autoreleased objects. release objects directly (using the release method) instead of indirectly (using theautorelease method) whenever possible. Releasing objects directly reclaims the memory occupied by the object immediately. Conversely, objects released using the autorelease method stay in memory until you explicitly drain the current autorelease pool or until the next iteration of the current run loop. Thus, creating large numbers of autoreleased objects during one iteration of a run loop can greatly increase memory pressure. Impose size limits on Avoid loading a large resource file when a smaller one will do. Instead of using a resources. high-resolution image, use one that is appropriately sized for iOS-based devices. If you must use large resource files, find ways to load only the portion of the file that you need at any given time. For example, rather than load the entire file into memory, use the mmap and munmap functions to map portions of the file into and out of memory. For more information about mapping files into memory, see File-System Performance Guidelines. Avoid unbounded problem sets. Unbounded problem sets might require an arbitrarily large amount of data to compute. If the set requires more memory than is available, your app may be unable to complete the calculations. Your apps should avoid such sets whenever possible and work on problems with known memory limits.
For detailed information on how to allocate memory in iOS apps and for more information on autorelease pools, see Cocoa Objects in Cocoa Fundamentals Guide.
108
CHAPTER 7
Performance Tuning
The CPU Wi-Fi, Bluetooth, and baseband (EDGE, 3G) radios The Core Location framework The accelerometers
109
CHAPTER 7
Performance Tuning
The disk
The goal of your optimizations should be to do the most work you can in the most efficient way possible. You should always optimize your apps algorithms using Instruments. But even the most optimized algorithm can still have a negative impact on a devices battery life. You should therefore consider the following guidelines when writing your code:
Avoid doing work that requires polling. Polling prevents the CPU from going to sleep. Instead of polling, use the NSRunLoop or NSTimer classes to schedule work as needed. Leave the idleTimerDisabled property of the shared UIApplication object set to NO whenever possible. The idle timer turns off the devices screen after a specified period of inactivity. If your app does not need the screen to stay on, let the system turn it off. If your app experiences side effects as a result of the screen being turned off, you should modify your code to eliminate the side effects rather than disable the idle timer unnecessarily. Coalesce work whenever possible to maximize idle time. It generally takes less power to perform a set of calculations all at once than it does to perform them in small chunks over an extended period of time. Doing small bits of work periodically requires waking up the CPU more often and getting it into a state where it can perform your tasks. Avoid accessing the disk too frequently. For example, if your app saves state information to the disk, do so only when that state information changes, and coalesce changes whenever possible to avoid writing small changes at frequent intervals. Do not draw to the screen faster than is needed. Drawing is an expensive operation when it comes to power. Do not rely on the hardware to throttle your frame rates. Draw only as many frames as your app actually needs. If you use the UIAccelerometer class to receive regular accelerometer events, disable the delivery of those events when you do not need them. Similarly, set the frequency of event delivery to the smallest value that is suitable for your needs. For more information, see Event Handling Guide for iOS.
The more data you transmit to the network, the more power must be used to run the radios. In fact, accessing the network is the most power-intensive operation you can perform. You can minimize that time by following these guidelines:
Connect to external network servers only when needed, and do not poll those servers. When you must connect to the network, transmit the smallest amount of data needed to do the job. Use compact data formats, and do not include excess content that simply is ignored. Transmit data in bursts rather than spreading out transmission packets over time. The system turns off the Wi-Fi and cell radios when it detects a lack of activity. When it transmits data over a longer period of time, your app uses much more power than when it transmits the same amount of data in a shorter amount of time. Connect to the network using the Wi-Fi radios whenever possible. Wi-Fi uses less power and is preferred over cellular radios. If you use the Core Location framework to gather location data, disable location updates as soon as you can and set the distance filter and accuracy levels to appropriate values. Core Location uses the available GPS, cell, and Wi-Fi networks to determine the users location. Although Core Location works hard to
110
CHAPTER 7
Performance Tuning
minimize the use of these radios, setting the accuracy and filter values gives Core Location the option to turn off hardware altogether in situations where it is not needed. For more information, see Location Awareness Programming Guide. The Instruments app includes several instruments for gathering power-related information. You can use these instruments to gather general information about power consumption and to gather specific measurements for hardware such as the Wi-Fi and Bluetooth radios, GPS receiver, display, and CPU. For more information about using these instruments, see Instruments User Guide.
Write only the portions of the file that changed, and aggregate changes when you can. Avoid writing out the entire file just to change a few bytes. When defining your file format, group frequently modified content together to minimize the overall number of blocks that need to be written to disk each time. If your data consists of structured content that is randomly accessed, store it in a Core Data persistent store or a SQLite database, especially if the amount of data you are manipulating could grow to more than a few megabytes.
Avoid writing cache files to disk. The only exception to this rule is when your app quits and you need to write state information that can be used to put your app back into the same state when it is next launched.
111
CHAPTER 7
Performance Tuning
For protocols you control, define your data formats to be as compact as possible. Avoid using chatty protocols. Transmit data packets in bursts whenever you can.
Cellular and Wi-Fi radios are designed to power down when there is no activity. Depending on the radio, though, doing so can take several seconds. If your app transmits small bursts of data every few seconds, the radios may stay powered up and continue to consume power, even when they are not actually doing anything. Rather than transmit small amounts of data more often, it is better to transmit a larger amount of data once or at relatively large intervals. When communicating over the network, packets can be lost at any time. Therefore, when writing your networking code, you should be sure to make it as robust as possible when it comes to failure handling. It is perfectly reasonable to implement handlers that respond to changes in network conditions, but do not be surprised if those handlers are not called consistently. For example, the Bonjour networking callbacks may not always be called immediately in response to the disappearance of a network service. The Bonjour system service immediately invokes browsing callbacks when it receives a notification that a service is going away, but network services can disappear without notification. This situation might occur if the device providing the network service unexpectedly loses network connectivity or the notification is lost in transit.
Using Wi-Fi
If your app accesses the network using the Wi-Fi radios, you must notify the system of that fact by including the UIRequiresPersistentWiFi key in the apps Info.plist file. The inclusion of this key lets the system know that it should display the network selection dialog if it detects any active Wi-Fi hot spots. It also lets the system know that it should not attempt to shut down the Wi-Fi hardware while your app is running.
112
CHAPTER 7
Performance Tuning
To prevent the Wi-Fi hardware from using too much power, iOS has a built-in timer that turns off the hardware completely after 30 minutes if no running app has requested its use through the UIRequiresPersistentWiFi key. If the user launches an app that includes the key, iOS effectively disables the timer for the duration of the apps life cycle. As soon as that app quits or is suspended, however, the system reenables the timer. Note: Note that even when UIRequiresPersistentWiFi has a value of true, it has no effect when the device is idle (that is, screen-locked). The app is considered inactive, and although it may function on some levels, it has no Wi-Fi connection. For more information on the UIRequiresPersistentWiFi key and the keys of the Info.plist file, see Figure 6-1 (page 100).
Your apps information property list (Info.plist) file contains the UIRequiresPersistentWiFi key and the value of that key is set to true. Your app launches while the device is currently in airplane mode. Wi-Fi on the device has not been manually reenabled after the switch to airplane mode.
113
CHAPTER 7
Performance Tuning
114
APPENDIX A
The iOS environment affects several aspects of how you design your app. Understanding some key aspects should help you when writing your code.
115
APPENDIX A
Multitasking Support
In iOS 4 and later, multitasking allows apps to run in the background even when they are not visible on the screen. Most background apps reside in memory but do not actually execute any code. These apps are suspended by the system shortly after entering the background to preserve battery life. Apps can ask the system for background execution time in a number of ways, though. For an overview of multitasking and what you need to do to support it, see Background Execution and Multitasking (page 51).
Security
The security infrastructure in iOS is there to protect your apps data and the system as a whole. Security breaches can and will happen, so the first line of defense in iOS is to minimize the damage caused by such breaches by securing each app separately in its own sandbox. But iOS provides other technologies, such as encryption and certificate support, to help you protect your data at an even more fundamental level. For an introduction to security and how it impacts the design of your app, see Security Overview.
116
Security
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
APPENDIX A
Figure A-1
...
...
App
App Sandbox
...
App Sandbox
App
...
Important: The purpose of a sandbox is to limit the damage that a compromised app can cause to the system. Sandboxes do not prevent attacks from happening to a particular app and it is still your responsibility to code defensively to prevent attacks. For example, if your app does not validate user input and there is an exploitable buffer overflow in your input-handling code, an attacker could still hijack your app or cause it to crash. The sandbox only prevents the hijacked app from affecting other apps and other parts of the system.
Keychain Data
A keychain is a secure, encrypted container for passwords and other secrets. The keychain is intended for storing small amounts of sensitive data that are specific to your app. It is not intended as a general-purpose mechanism for encrypting and storing data. Keychain data for an app is stored outside of the apps sandbox. When the user backs up app data using iTunes, the keychain data is also backed up. Before iOS 4.0, keychain data could only be restored to the device from which the backup was made. In iOS 4.0 and later, a keychain item that is password protected can be restored to a different device only if its accessibility is not set to kSecAttrAccessibleAlwaysThisDeviceOnly or any other value that restricts it to the current device. Upgrading an app does not affect that apps keychain data. For more on the iOS keychain, see Keychain Services Concepts in Keychain Services Programming Guide.
Security
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
117
APPENDIX A
118
Security
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
REVISION HISTORY
This table describes the changes to iOS App Programming Guide. Date 2011-10-12 Notes Added information about features introduced in iOS 5.0. Reorganized book and added more design-level information. Added high-level information about iCloud and how it impacts the design of applications. 2011-02-24 2010-12-13 2010-11-15 Added information about using AirPlay in the background. Made minor editorial changes. Incorporated additional iPad-related design guidelines into this document. Updated the information about how keychain data is preserved and restored. 2010-08-20 Fixed several typographical errors and updated the code sample on initiating background tasks. Updated the guidance related to specifying application icons and launch images. Changed the title from iPhone Application Programming Guide. 2010-06-14 Reorganized the book so that it focuses on the design of the core parts of your application. Added information about how to support multitasking in iOS 4 and later. For more information, see Core App Objects (page 21). Updated the section describing how to determine what hardware is available. Added information about how to support devices with high-resolution screens. Incorporated iPad-related information. 2010-02-24 2010-01-20 Made minor corrections. Updated the Multimedia Support chapter with improved descriptions of audio formats and codecs. Moved the iPhone specific Info.plist keys to Information Property List Key Reference. Updated the Multimedia Support chapter for iOS 3.1.
2010-06-30
2009-10-19
119
2011-10-12 | 2011 Apple Inc. All Rights Reserved.
REVISION HISTORY
Date 2009-06-17
Notes Added information about using the compass interfaces. Moved information about OpenGL support to OpenGL ES Programming Guide for iOS. Updated the list of supported Info.plist keys.
2009-05-14
Updated for iOS 3.0. Added code examples to "Copy and Paste Operations" in the Event Handling chapter. Added a section on keychain data to the Files and Networking chapter. Added information about how to display map and email interfaces. Made various small corrections.
2009-01-06
Fixed several typos and clarified the creation process for child pages in the Settings application. Added guidance about floating-point math considerations Updated information related to what is backed up by iTunes.
2008-11-12
2008-10-15
Reorganized the contents of the book. Moved the high-level iOS information to iOS Technology Overview. Moved information about the standard system URL schemes to Apple URL Scheme Reference. Moved information about the development tools and how to configure devices to iOS App Development Workflow Guide. Created the Core Application chapter, which now introduces the application architecture and covers much of the guidance for creating iPhone applications. Added a Text and Web chapter to cover the use of text and web classes and the manipulation of the onscreen keyboard. Created a separate chapter for Files and Networking and moved existing information into it. Changed the title from iPhone OS Programming Guide.
2008-07-08
New document that describes iOS and the development process for iPhone applications.
120
2011-10-12 | 2011 Apple Inc. All Rights Reserved.