Getting Started with Document-based SwiftUI Apps


Getting Started with Document-based SwiftUI Apps

Document-based apps let people create documents they can share with others. Examples of document-based apps are text editors, spreadsheets and video editors. Learn the basics of making document-based SwiftUI apps in this article.

Creating a Project in Xcode

The iOS, Mac, and Multiplatform project categories have a Document App project template. Select that template and click the Next button to create a document app.

Multiplatform document apps automatically use SwiftUI. If you choose an iOS or Mac document app, make sure you choose SwiftUI from the Interface menu. Click the Next button to finish creating the project.

The Project Contents

When you create a document app SwiftUI project, Xcode creates the following files for the project:

  • A file for the app, which should be the project name followed by App.
  • A content view file, which is the main view for the project.
  • A file for the document, which should be the project name followed by Document.

You will most likely want to change the name of the document struct.

Examine the Document Struct

If you open the file for the document, it should look similar to the following code:

import SwiftUI
import UniformTypeIdentifiers
extension UTType {
  static var exampleText: UTType {
  UTType(importedAs: "com.example.plain-text")
  }
}
struct SwiftUITestProjectDocument: FileDocument {
  var text: String
  init(text: String = "Hello, world!") {
    self.text = text
  }
  static var readableContentTypes: [UTType] { [.exampleText] }
  init(configuration: ReadConfiguration) throws {
    guard let data = configuration.file.regularFileContents,
      let string = String(data: data, encoding: .utf8)
    else {
      throw CocoaError(.fileReadCorruptFile)
    }
    text = string
  }
  func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
    let data = text.data(using: .utf8)!
    return .init(regularFileWithContents: data)
  }
}

Xcode configures the document to be a plain text editor.

Changing the Document Type

Unless you're writing a plain text editor, you'll have to change the document type. Take a look at the code that defines the document type.

extension UTType {
  static var exampleText: UTType {
    UTType(importedAs: "com.example.plain-text")
  }
}

Change the variable name from exampleText. Change the identifier from com.example.plain-text to the unique identifier for the document type. Change any code that refers to exampleText with the new variable name.

You also must update the document type for the target in Xcode.

  1. Select the project from the project navigator to open the project editor.
  2. Select the app target from the left side of the project editor.
  3. Click the Info button at the top of the project editor.

There are three sections related to document types in the project editor: Document Types, Exported Type Identifiers, and Imported Type Identifiers. Xcode includes a document type and an imported type identifier for new document app projects.

In the Document Types section, give your document type a name in the Name text field. Make sure the value in the Identifier text field matches the identifier you used when defining the UTType in code.

In the Imported Type Identifiers section, enter the document type name in the Description text field. Enter the file extension in the Extensions text field, omitting the leading dot. Use the same identifier you set in the Document Types section. If your document type conforms to a base UTI, enter it in the Conforms To text field.

If you create a custom file format for your document, you must add an Exported Type Identifier for the document. Enter the same information you entered in the Imported Type Identifiers section: description, extensions, identifiers, and possibly conformance to a base UTI.

Saving the Document

Specify the file formats your document can save to. Xcode fills in a readableContentTypes variable with the file types your app can read. By default these are the same types you'll be able to save to.

If your app saves or exports to types that aren't in readableContentTypes, you'll have to add a writableContentTypes property with the file types you can save to. An image editor may have something like the following:

static var writableContentTypes: [UTType] { [.myImageFormat, .jpeg, .png] }

Xcode includes a fileWrapper function in the document's Swift file. This function is where you save the document.

func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
  let data = text.data(using: .utf8)!
  return .init(regularFileWithContents: data)
}

In the function you must convert your document's contents to a Data object and write the contents to a file wrapper. The last line in the fileWrapper function demonstrates how to save a document as a single file.

Loading the Document

The init that takes a read configuration is where you add the code to load a document.

init(configuration: ReadConfiguration) throws {
  guard let data = configuration.file.regularFileContents,
    let string = String(data: data, encoding: .utf8)
  else {
    throw CocoaError(.fileReadCorruptFile)
  }
  text = string
}

Read the file contents into a Data object. Convert the data to set the document's data properties.

Next Steps

The following articles have more information on making document-based SwiftUI apps:

I have a WikiDemo app on GitHub as an example of a multi-platform, document-based SwiftUI app with a master-detail interface.

Swift Dev Journal

Subscribe and get exclusive articles on Swift development, a free guide on moving from tutorials to making your first app, notices of sales on books, and anything I decide to add in the future.

Read more from Swift Dev Journal

If you find your app becomes unresponsive at times, it can be frustrating to find the cause. Instruments includes a Hangs instrument that reports hangs to help you find and fix hangs. This article shows you how to use the Hangs and Time Profiler instruments to find hangs and find the code causing the hangs. Profiling Your App In Xcode press Cmd-I to build and profile your app with Instruments. When Instruments launches, it will ask you to choose a template for profiling. Select the Time...

Saving App Data in Property List Files Your app needs to save data. There's too much data to use User Defaults. Using SwiftData or Core Data would be overkill. One solution is to save the data in property list files. This article shows you how to save your app's data in property list files. Use the PropertyListEncoder Class if you can If the data you want to save conforms to the Codable protocol, use the PropertyListEncoder class to save the data. Encoding data with PropertyListEncoder...

Working with Lists in Multiplatform SwiftUI Apps One of SwiftUI's best features is you can use it to make apps that run on both iOS and Mac. Almost every SwiftUI article you find online is about iOS development, but most of the material also applies to Mac as well. Lists are one area of SwiftUI where there are large differences between iOS and Mac. If you read an article about lists and try to use the code in a Mac app, you'll run into problems. This article provides guidance on writing list...