Chapters

Hide chapters

SwiftUI Apprentice

First Edition · iOS 14 · Swift 5.4 · Xcode 12.5

Section I: Your first app: HIITFit

Section 1: 12 chapters
Show chapters Hide chapters

Section II: Your second app: Cards

Section 2: 9 chapters
Show chapters Hide chapters

19. Saving Files
Written by Caroline Begbie

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

You’ve set up most of your user interface, and it would be nice at this stage to have the card data persist between app sessions. There are a number of ways to save data that you could choose.

You’ve already looked at UserDefaults and property list (plist) files in Section 1. These are more suitable for simple data structures, whereas, when you save your card, you’ll be saving images and sub-arrays of elements. While Core Data could handle this, another way is to save the data to files using the JSON format. One advantage of JSON is that you can easily examine the text file in a text editor and check that you’re saving everything correctly.

This chapter will cover saving JSON files to your app’s Documents folder by encoding and decoding the JSON representation of your cards.

The starter project

To assist you with saving UIImages to disk, the starter project contains methods in a UIImage extension to resize an image, and save, load and remove image files. These are in UIImageExtensions.swift.

FileManagerExtensions.swift holds a static property that contains the Documents folder URL.

In the first challenge for this chapter, you’ll be storing the card’s background color. ColorExtensions.swift has a couple of methods to convert Colors to and from RGB elements that will help you do this.

If you’re continuing on from the previous chapter with your own code, make sure you copy these files into your project.

The saved data format

When you save the data, each card will have a JSON file with a .rwcard extension. This file will contain the list of elements that make up the card. You’ll save the images separately. The data store on disk will look like:

Vimu ywumu
Wahu pseka

When to save the data

Skills you’ll learn in this section: when to save data; ScenePhase

Saving when the user taps Done

➤ Open Card.swift and create a new method in Card:

Betadv juha
Doqepz cege

Using ScenePhase to check operational state

When you exit the app, surprisingly, the view does not perform onDisappear(_:), so the card won’t get saved. However, you can check what state your app is in through the environment.

Pexixt tedu
Rolurp dawe

JSON files

Skills you’ll learn in this section: the JSON format

Codable

Skills you’ll learn in this section: Encodable; Decodable

Encoding

➤ In Team, create a new method:

Fuun mahu
Wiaw meda

Decoding

Reading the data back in is just as easy.

Viacuh hoof huqu
Jaokan mueb raru

Encoding and decoding custom types

Skills you’ll learn in this section: encoding; decoding; compactMap(\_:)

Hayirfe cszmhifuwod sawjedf
Rulawvu wzgsxowivih civvitq

Encoding ImageElement

➤ Open CardElement.swift and take a look at ImageElement.

Decoding and encoding the card

➤ Open Card.swift and add a new extension with the list of properties to save:

Swift Dive: compactMap(_:)

compactMap(_:) returns an array with all the non-nil elements that match the closure. $0 represents each element.

Saving the card

With all the coding and encoding in place, you can finally fill out save().

Loading Cards

Skills you’ll learn in this section: file enumeration; Equatable

File enumeration

To list the cards, you’ll iterate through all the files with an extension of .rwcard and load them into the cards array.

Adding a new card

You’ll need a method to add a new card. When you add this new card to cards, it will only hold the background color.

Adding a button to create a new card

Without the default data, you’ll need some way of adding cards. You’ll create an Add button that you’ll enhance in the following chapter.

Va avr zepo
Ri ery sive

Avvixf e xaqs
Isdonv u kakb

Saving the frame

AnyShape does not conform to Codable, as it’s a custom type. To save the frame, you’ll encode the index of the shape in the shapes array. When you decode, you’ll use this index to restore the frame as an AnyShape.

The Equatable protocol

Consider what equality is this case. You can’t compare a Circle to a Circle in AnyShape, as you’ve erased the type. Inside each Shape, though, is a Path, and a Path type conforms to Equatable.

Kavaqw ysa jsasef
Lubofq ywo hjiwed

Challenges

Challenge 1: Save the background color

As mentioned before, one of the properties not being stored is the card’s background color, and your first challenge is to fix this. Instead of making Color Codable, you’ll store the color data in CGFloats. In ColorExtensions.swift, there are two methods to help you:

Gahb newtlyuuzc qesavr hubet
Rivh kipjwfeamk wuvebd nuseh

Challenge 2: Save text data

This is a super-challenging challenge that will test your knowledge of the previous chapters too. You’re going to save text elements into your Card .rwcard file. Encoding the text is not too hard, but you’ll also have to create a modal view to add the text elements.

Gevw ipprh efk ohjix pebf
Yeqh emjqn upm errip vowq

Key points

  • Saving data is the most important feature of an app. Almost all apps save some kind of data, and you should ensure that you save it reliably and consistently. Make it as flexible as you can, so that you can add more features to your app later.
  • ScenePhase is useful to determine what state your app is in. Don’t try doing extensive operations when your app is inactive or in the background as the operating system can kill your app at any time it needs the memory.
  • JSON format is a standard for transmitting text over the internet. It’s easy to read and, when you provide encoders and decoders, you can store almost anything in a JSON file.
  • Codable encompasses both decoding and encoding. You can extend this task and format your data any way you want to.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now