Copy, Cut, and Paste Operations
Users can copy text, images, or other data in one app and paste that data to another location within the same app or in a different app. You can, for example, copy a person’s address in an email message and paste it into the appropriate field in the Contacts app. The UIKit framework implements copy-cut-paste in the UITextView
, and UITextField
classes. If you want this behavior in your own apps, you can either use objects of these classes or implement copy-cut-paste yourself.
The following sections describe the programmatic interfaces of the UIKit that you use for copy, cut, and paste operations and explain how they are used.
Copy-Paste Operations in UIKit
Several classes and an informal protocol of the UIKit framework give you the methods and mechanisms you need to implement copy, cut, and paste operations in your app:
The
UIPasteboard
class provides pasteboards: protected areas for sharing data within an app or between apps. The class offers methods for writing and reading items of data to and from a pasteboard.The
UIMenuController
class displays an edit menu above or below the selection to be copied, cut, or pasted into. The default commands of the edit menu are (potentially) Copy, Cut, Paste, Select, and Select All. You can also add custom menu items to the edit menu (see Adding Custom Items to the Edit Menu).The
UIResponder
class declares the methodcanPerformAction:withSender:
. Responder classes can implement this method to show and remove commands of the edit menu based on the current context.The
UIResponderStandardEditActions
informal protocol declares the interface for handling copy, cut, paste, select, and select-all commands. When users tap one of the commands in the edit menu, the correspondingUIResponderStandardEditActions
method is invoked.
Pasteboard Concepts
A pasteboard is a standardized mechanism for exchanging data within apps or between apps. The most familiar use for pasteboards is handling copy, cut, and paste operations:
When a user selects data in an app and chooses the Copy (or Cut) menu command, the selected data is placed onto a pasteboard.
When the user chooses the Paste menu command (either in the same or a different app), the data on a pasteboard is copied to the current app from the pasteboard.
In iOS, a pasteboard is also used to support Find operations. Additionally, you may use pasteboards to transfer data between apps using custom URL schemes instead of copy, cut, and paste commands; see Updating Your Info.plist Settings for information about this technique.
Regardless of the operation, the basic tasks you perform with a pasteboard object are to write data to a pasteboard and to read data from a pasteboard. Although these tasks are conceptually simple, they mask a number of important details. The main complexity is that there may be a number of ways to represent data, and this complexity leads to considerations of efficiency. These and other issues are discussed in the following sections.
Named Pasteboards
Pasteboards may be public or private. Public pasteboards are called system pasteboards; private pasteboards are created by apps, and hence are called app pasteboards. Pasteboards must have unique names. UIPasteboard
defines two system pasteboards, each with its own name and purpose:
UIPasteboardNameGeneral
is for cut, copy, and paste operations involving a wide range of data types. You can obtain a singleton object representing the General pasteboard by invoking thegeneralPasteboard
class method.UIPasteboardNameFind
is for search operations. The string currently typed by the user in the search bar (UISearchBar
) is written to this pasteboard, and thus can be shared between apps. You can obtain an object representing the Find pasteboard by calling thepasteboardWithName:create:
class method, passing inUIPasteboardNameFind
for the name.
Typically you use one of the system-defined pasteboards, but if necessary you can create your own app pasteboard using pasteboardWithName:create:
If you invoke pasteboardWithUniqueName
, UIPasteboard
gives you a uniquely-named app pasteboard. You can discover the name of a pasteboard through its name
property.
Pasteboard Persistence
Pasteboards can be persistent. When a pasteboard is persistent, it continues to exist past app terminations and across system reboots. System pasteboards are persistent. Although app pasteboards by default are not persistent, an app can mark them as persistent by setting the persistent
property to YES
. App pasteboards that are not persistent only last until the owning (creating) app quits. A persistent app pasteboard is removed when the app that created it is uninstalled.
Pasteboard Owner and Items
The object that last put data onto the pasteboard is referred to as the pasteboard owner. Each piece of data placed onto a pasteboard is considered a pasteboard item. The pasteboard can hold single or multiple items. Apps can place or retrieve as many items as they wish. For example, say a user selection in a view contains both text and an image. The pasteboard lets you copy the text and the image to the pasteboard as separate items. An app reading multiple items from a pasteboard can choose to take only those items that it supports (the text, but not the image, for example).
Representations and UTIs
Pasteboard operations are often carried out between two different apps. Neither app is required to know about the other, including the kinds of data it can handle. To maximize the potential for sharing, a pasteboard can hold multiple representations of the same pasteboard item. For example, a rich text editor might provide HTML, PDF, and plain-text representations of the copied data. An item on a pasteboard includes all representations of that data item that the app can provide.
Each representation of a pasteboard item is typically identified by a Unique Type Identifier (UTI). (A UTI is simply a string that uniquely identifies a particular data type.) The UTI provides a common means to identify data types. If you have a custom data type you wish to support, you must create a unique identifier for it. For this, you could use reverse-DNS notation for your representation-type string to ensure uniqueness; for example, a custom representation type could be com.myCompany.myApp.myType
. For more information on UTIs, see Uniform Type Identifiers Overview.
For example, suppose an app supported selection of rich text and images. It may want to place on a pasteboard both rich text and Unicode versions of a text selection and different representations of an image selection. Each representation of each item is stored with its own data, as shown in Figure 5-1.
In general, to maximize the potential for sharing, pasteboard items should include as many different representations as possible.
A pasteboard reader must find the data type that best suits its capabilities (if any). Typically, this means selecting the richest type available. For example, a text editor might provide HTML (rich text) and plain-text representations of copied text data. An app that supports rich text should retrieve the HTML representation and an app that only supports plain text should retrieve the plain-text version.
Change Count
The change count is a per-pasteboard variable that increments every time the contents of the pasteboard changes—specifically, when items are added, modified, or removed. By examining the change count (through the changeCount
property), an app can determine whether the current data in the pasteboard is the same as the data it last received. Every time the change count is incremented, the pasteboard sends a notification to interested observers.
First Steps: Identify the Selection and Display the Edit Menu
If you are going to copy, cut, or paste something, you first must select it. (A paste operation often operates on an empty selection such a caret, indicating a position within a collection of items.) After selecting an item—and visually indicating the selection—you should display the edit menu. The edit menu is a system menu that can potentially have the following commands in it: Copy, Cut, Paste, Select, and Select All. The edit menu points at the selection. When the user taps a menu item, the appropriate UIResponderStandardEditActions
method implementation (such as cut:
or paste:
) is invoked.
For more about selections and to learn how to display and manage the edit menu, see Managing the Selection and the Edit Menu.
Copying and Cutting the Selection
When users tap the Copy or Cut command of the edit menu, the system invokes the copy:
or cut:
method (respectively) of the responder object that implements it. Usually the first responder—your custom view—implements these methods, but if the first responder doesn’t implement them, the message travels up the responder chain in the usual fashion. Note that the UIResponderStandardEditActions
informal protocol declares these methods.
In response to a copy:
or cut:
message, you write the object or data represented by the selection to the pasteboard in as many different representations as you can. This operation involves the following steps (which assume a single pasteboard item):
From the selection, identify or obtain the object or the binary data corresponding to the object.
Binary data must be encapsulated in an
NSData
object. If you’re going to write another type of object to the pasteboard, it must be a property-list object—that is, an object of one of the following classes:NSString
,NSArray
,NSDictionary
,NSDate
,NSNumber
, orNSURL
. (For more on property-list objects, see Property List Programming Guide.)If possible, generate one or more other representations of the object or data.
For example, if in the previous step you created a
UIImage
object representing a selected image, you could use theUIImageJPEGRepresentation
andUIImagePNGRepresentation
functions to convert the image to a different representation.Obtain a pasteboard object.
In many cases, this is the general pasteboard, which you can get through the
generalPasteboard
class method.Assign a suitable UTI for each representation of data written to the pasteboard item.
See Pasteboard Concepts for a discussion of this subject.
Write the data to the first pasteboard item for each representation type:
To write a data object, send a
setData:forPasteboardType:
message to the pasteboard object.To write a property-list object, send a
setValue:forPasteboardType:
message to the pasteboard object.
If the command is Cut (
cut:
method), remove the object represented by the selection from the app’s data model and update your view.
Listing 5-1 shows implementations of the copy:
and cut:
methods. The cut:
method invokes the copy:
method and then removes the selected object from the view and the data model. Note that the copy:
method archives a custom object to obtain an NSData
object that it can pass to the pasteboard in setData:forPasteboardType:
.
Listing 5-1 Copying and cutting operations
- (void)copy:(id)sender { |
UIPasteboard *gpBoard = [UIPasteboard generalPasteboard]; |
ColorTile *theTile = [self colorTileForOrigin:currentSelection]; |
if (theTile) { |
NSData *tileData = [NSKeyedArchiver archivedDataWithRootObject:theTile]; |
if (tileData) |
[gpBoard setData:tileData forPasteboardType:ColorTileUTI]; |
} |
} |
- (void)cut:(id)sender { |
[self copy:sender]; |
ColorTile *theTile = [self colorTileForOrigin:currentSelection]; |
if (theTile) { |
CGPoint tilePoint = theTile.tileOrigin; |
[tiles removeObject:theTile]; |
CGRect tileRect = [self rectFromOrigin:tilePoint inset:TILE_INSET]; |
[self setNeedsDisplayInRect:tileRect]; |
} |
} |
Pasting the Selection
When users tap the Paste command of the edit menu, the system invokes the paste:
method of the responder object that implements it. Usually the first responder—your custom view—implements this method, but if the first responder doesn’t implement it, the message travel up the responder in the usual fashion. The paste:
method is declared by the UIResponderStandardEditActions
informal protocol.
In response to a paste:
message, you read an object from the pasteboard in a representation that your app supports. Then you add the pasted object to the app’s data model and display the new object in the view in the user-indicated location. This operation involves the following steps (which assume a single pasteboard item):
Obtain a pasteboard object.
In many cases, this is the general pasteboard, which you can get through the
generalPasteboard
class method.Verify that the first pasteboard item contains data in a representation that your app can handle by calling the
containsPasteboardTypes:
method or thepasteboardTypes
method and then examining the returned array of types.Note that you should have already performed this step in your implementation of
canPerformAction:withSender:
.If the first item of the pasteboard contains data that the app can handle, call one of the following methods to read it:
dataForPasteboardType:
if the data to be read is encapsulated in anNSData
object.valueForPasteboardType:
if the data to be read is encapsulated in a property-list object (see Copying and Cutting the Selection).
Add the object to the app’s data model.
Display a representation of the object in the user interface at the location specified by the user.
Listing 5-2 is an example of an implementation of the paste:
method. It does the reverse of the combined cut:
and copy:
methods. The custom view first sees whether the general pasteboard holds its custom representation of data; if it does, it then reads the data from the pasteboard, adds it to the app’s data model, and marks part of itself—the current selection—for redrawing.
Listing 5-2 Pasting data to a selection
- (void)paste:(id)sender { |
UIPasteboard *gpBoard = [UIPasteboard generalPasteboard]; |
NSArray *pbType = [NSArray arrayWithObject:ColorTileUTI]; |
ColorTile *theTile = [self colorTileForOrigin:currentSelection]; |
if (theTile == nil && [gpBoard containsPasteboardTypes:pbType]) { |
NSData *tileData = [gpBoard dataForPasteboardType:ColorTileUTI]; |
ColorTile *theTile = (ColorTile *)[NSKeyedUnarchiver unarchiveObjectWithData:tileData]; |
if (theTile) { |
theTile.tileOrigin = self.currentSelection; |
[tiles addObject:theTile]; |
CGRect tileRect = [self rectFromOrigin:currentSelection inset:TILE_INSET]; |
[self setNeedsDisplayInRect:tileRect]; |
} |
} |
} |
Ending an Operation
When your implementation of the cut:
, copy:
or paste:
command returns, the edit menu is automatically hidden. You can programmatically keep it visible if you want. For more information, see Dismissing the Edit Menu
Copyright © 2018 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2018-01-16