Saving Data in iOS

May 31 2022 · Swift 5.5, iOS 15, Xcode 13

Part 2: JSON

12. Challenge: Decoding JSON Arrays

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 11. JSON Decoding Next episode: 13. Saving On Device

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 12. Challenge: Decoding JSON Arrays

This course was originally recorded in April 2020. It has been reviewed and all content and materials updated as of November 2021.

Transcript: 12. Challenge: Decoding JSON Arrays

If your type is Encodable, not only can you decode an instance of it in JSON, you can store an array of its instances in JSON.

For this challenge, update your loadJSON() method in ContentView.swift to use the new Tasks.json and PrioritizedTasks.json files in order to load a Task array, and a PrioritizedTask array.

Print out the results to the console in order to see the loaded arrays. Have fun!

The first thing I did was to update the guard statement inside loadJSON to point to the new JSON files to use.

let tasksJSONURL = Bundle.main.url(forResource: "Tasks", withExtension: "json")
let prioritizedTaskJsSONURL = Bundle.main.url(forResource: "PrioritizedTasks", withExtension: "json")

Then, I updated the Data initializers to use the new constant names, as well some of the constant’s names to reflect that multiple tasks and prioritized tasks are being loaded.

let tasksData = try Data(contentsOf: tasksJSONURL)
let tasks = try decoder.decode(Task.self, from: tasksData)
print(tasks)

let prioritizedTasksData = try Data(contentsOf: prioritizedTasksJSONURL)
let prioritizedTasks = try decoder.decode(TaskStore.PrioritizedTasks.self, from: prioritizedTasksData)
print(prioritizedTasks)

Finally, instead of decoding a type of Task or PrioritizedTask, I updated this to reflect that an array of each is being loaded.

let tasks = try decoder.decode([Task].self, from: tasksData)

let prioritizedTasks = try decoder.decode([TaskStore.PrioritizedTasks].self, from: prioritizedTasksData)

Run your app with these changes and check out the console.

There is now a lot more content in the console to reflect the arrays being loaded.

With the challenge completed, how about you start updating the TaskStore to use the prioritized tasks from the JSON file and not hard-code them in the prioritizedTasks property? First, start by removing the onAppear method in the body of ContentView.

Next, select all of your loadJSON’s method code and cut it by hitting Command + X

Cut the loadJSON method.

Content view should now look just as it was before adding your method for loading JSON data. Switch over to the TaskStore.swift file and paste your loadJSON method.

Xcode is showing a bunch of errors about unresolved identifiers. This can be addressed by importing the Foundation framework. So go ahead and add that to the top of the file

import Combine
import Foundation

Exellent, those errors should no be gone. Time to clean up the method a little bit. Start by renaming it to loadJSONPrioritizedTasks to better reflect what you’ll be loading, or decoding.

private func loadJSONPrioritizedTasks

You only need a single URL to load your prioritized tasks, so go ahead and update the guard statement to reflect that.

guard let tasksJSONURL = Bundle.main.url(forResource: "PrioritizedTasks", withExtension: "json") else {
  return
}

The decoder constant as well as the catch statement can remain the same, but you can also clean things up a bit within the do block when decoding the JSON array.

let tasksData = try Data(contentsOf: tasksJSONURL)
prioritizedTasks = try decoder.decode([PrioritizedTasks].self, from: tasksData)

Note how, when decoding, you store the array of prioritized tasks in the TaskStore’s prioritizedTasks property. That property, however, has some hard-coded data already. Clean that up so it starts out as an empty array instead.

@Published var prioritizedTasks: [PrioritizedTasks] = []

Whereas before the compiler could infer the type, you now explicitly declare it as an array of PrioritizedTasks. Build and run the app.

It’s empty, why is that? the loadJSONPrioritizedTasks method is not getting called anywhere. A great place to do this is in an initializer for TaskStore.

init() {
  loadJSONPrioritizedTasks()
}

Now run your app again and check out the results. Excellent, your app no longer uses hard-coded data in your code, but instead is loading it from a file in your app’s bundle.