Universal Type Identifiers Tutorial for iOS: Importing and Exporting App Data
In this tutorial, you’ll learn how to export and import app data to and from your iOS app, as well as create custom file types and extensions. By Ehab Amer.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Universal Type Identifiers Tutorial for iOS: Importing and Exporting App Data
25 mins
- Getting Started
- Exploring the App
- Creating a Custom File Type
- Saving the New File Type
- Understanding the Uniform Type Identifier
- Registering Your New UTI
- Defining Import Types
- Importing Files to your App
- Using Scenes
- Working Without Scenes
- Defining Export Types
- Setting Up the Export Logic
- Switching from Import to Export
- Exporting Files with Activity View Controller
- Excluding Activity Types
- Exporting Files via Email
- Adding an Attachment
- Understanding the MIME Type
- Where to Go From Here?
Saving your app’s data is important, but sometimes simply saving won’t cut it. You’ll find that many users also want to export their data to another app or import app data from a file.
In this tutorial, you’ll learn how to export your app’s data to an email, share it as a file and import it back into your app.
Getting Started
Download the starter project for this tutorial by using the Download Materials button at the top or bottom of this page. Open TaskList.xcodeproj inside the Starter folder.
The project you’ll build is an app for saving and tracking tasks you don’t want to forget. It has basic functions such as adding, editing and deleting tasks, as well as marking them complete.
Exploring the App
Before you dive into the code, you should know a little about the project structure.
The project has everything you need to do basic exporting and importing of data. You’ll enhance this project by modifying the following two files:
- ContentView.swift is the view you see when you fist launch the app. It lists all the items in the data store with their priority.
- TaskStore.swift is the data store of the app. Whenever you change something in the list, like add an item or mark one as completed, the store saves its current contents into a plist file in the documents directory.
Build and run your project, and you’ll see no tasks under the four priority levels.
So, right now you don’t have any data to export. You could add items one by one, but that would be tedious. Instead, why not import an existing list of tasks? You’ll do just that. But before you can kick off the import, you’ll create a custom file type to facilitate the process.
Creating a Custom File Type
Your app should be able to identify files it can import. At the same time, it would be convenient for your users to be able to identify file types that are compatible with your app when they see them.
To achieve this, you’re going to create a new file extension and register the new file type as something your application can import. For this tutorial, your custom file type will be .RWTL, short for Ray Wenderlich Tasks List.
Saving the New File Type
The first step in this process is to use the custom file type in the app.
The sample project already includes code to save tasks to a file. Since Task
conforms to Codable
, it’s easy to use Swift’s built-in PropertyListEncoder
to encode a list of tasks into a property list Data
blob. You can then write the data to a file on the user’s device.
To see this at work, open TaskStore.swift and look at the two lines below the shared instance declaration:
// 1
static let fileExtension = "plist"
// 2
let tasksDocURL = URL(
fileURLWithPath: "PrioritizedTasks",
relativeTo: FileManager.documentsDirectoryURL)
.appendingPathExtension(fileExtension)
In these two lines, you’re:
- Storing the file extension as a static variable.
- Constructing the URL for reading and writing the list data with the file extension and saving it to a file named PrioritizedTasks.
Now change the first line so that it uses your new file extension:
static let fileExtension = "rwtl"
Build and run, but notice that nothing changed. Well, nothing that you can see just yet. Go ahead and add an item. After this, check the app’s documents directory you’ll see that it created a new rwtl file.
Finding the data folder can be a hassle if you navigate folder by folder. A better way is to print the value of tasksDocURL
before the TaskStore loads its prioritized tasks. To do this, add the following line to the top of TaskStore
‘s init
:
print(tasksDocURL)
Run the app. Then open Finder, type Shift-Command-G and copy the path from the console, without the starting file://
protocol.
Understanding the Uniform Type Identifier
You’re using a custom extension above (“rwtl”). You could have entered anything for your extension name and it would have worked. So how does the system know the app to use for each extension?
Take JPG images as an example. Both jpeg and jpg are valid extensions. It doesn’t make sense to register the same file with the same information for each extension. But how does the system know they’re the same type?
Apple created the Uniform Type Identifier for this very purpose. It enables you to define types than can have different identifiers and representations.
Registering Your New UTI
To register the new file type with your app:
- Select the project in the Project navigator.
- Select the app target (not the project item) from the Targets list.
- Click the Info tab.
In the Document Types section, add a new entry and configure it as follows:
- Name: TaskList Data
- Types: com.raywenderlich.TaskList.TaskListData
- Icon: click the + button and choose the only image available, its file name is icon-doc.png
-
Additional document type properties: Add two entries
- CFBundleTypeRole with type String and value Editor
- LSHandlerRank with type String and value Owner
- CFBundleTypeRole with type String and value Editor
- LSHandlerRank with type String and value Owner
This creates a new UTI called TaskList Data with an associated unique identifier and an icon. With the additional properties, you specify that TaskList is an editor for and owner of TaskList Data files, so that iOS knows to give it the largest level of control over these files.
Defining Import Types
So far, you defined a new UTI but didn’t enter any information about your new extension. You’ll do that next.
You’ll start with the import step before the export, though much of what you do here will also support the export process.
While still on the Info tab, look for the Imported UTIs section below Document Types. Add a new item in this section with the following information.
- Description: TaskList Data
- Identifier: com.raywenderlich.TaskList.TaskListData
- Conforms To: public.data
- Icon: click the + button and choose the only image available, its file name is icon-doc.png
- Additional imported UTI properties: Add one entry UTTypeTagSpecification of type Dictionary. Inside it, add one item with the key public.filename-extension of type Array and inside it add two values rwtl and RWTL.
With this, you connect the document type you created earlier with two file extensions: .rwtl and .RWTL. iOS will now launch your app when a user tries to use a file with one of these extensions. When defining imported UTIs, make sure the that identifier matches the types you defined in the Document Types section.
You also need to let iOS know about how you plan to import app data. Open Info.plist and add the following two keys:
- LSSupportsOpeningDocumentsInPlace with a value of NO, indicating that documents should be copied before they are imported into your app.
- UISupportsDocumentBrowser with a value of NO, indicating that your app is not a document-based app.
Build and run, then close the app in the simulator to show the home screen. Remember the PrioritizedTasks.rwtl file that you downloaded with the starter project? Try dropping that file onto the simulator.
Notice that this action launches the app. Awesome way to open files, huh? :]