1

New to IOS development and JSON stuff. I have a struct for Recipe which includes things like name, ingredients, instructions, etc. I have an array of Recipes. When my app is first run, I read data from a JSON file into the array of recipes so the app isn't empty at first. Throughout the app I append to the array of recipes. How would I go about writing the array back to the file everytime the array is changed? Here is some of the code and things I have tried.

Recipe Struct:

struct Recipe : Codable, Identifiable {
    var id: String
    var name: String
    var ingredients: [String]
    var instructions: [String]
    var category: String
    var imageName: String
}

Reading from JSON into recipe array:

import UIKit
import SwiftUI


var recipeData: [Recipe] = loadJson("recipeData.json")

func loadJson<T: Decodable>(_ filename: String) -> T {
    let data: Data
    guard let file = Bundle.main.url(forResource: filename,withExtension: nil)
    else {
        fatalError("\(filename) not found.")
    }
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Could not load \(filename): \(error)")
    }
    do {
        return try JSONDecoder().decode(T.self, from: data)
    } catch {
        fatalError("Unable to parse \(filename): \(error)")
    }
}

My attempt to write back to a json file once array is changed(appended to):

func writeJson(){
        var jsonArray = [String]()
        
        if let documentDirectory = FileManager.default.urls(for: .documentDirectory,
                                                            in: .userDomainMask).first {
            let pathWithFilename = documentDirectory.appendingPathComponent("test.json")
        
            for recipe in recipeData{
                do{
                    let encodedData = try JSONEncoder().encode(recipe)
                    let jsonString = String(data: encodedData, encoding: .utf8)
                    print(jsonString!)
                    jsonArray.append(jsonString!)
                    try jsonString!.write(to: pathWithFilename,
                                         atomically: true,
                                         encoding: .utf8)
                }catch{
                    print(error)
                }
            }
        }
    }

This all builds successfully but nothing is written to my tests.json file. I am very new so any help would be appreciated. Thank you.

1 Answer 1

1
 try jsonString!.write(to: pathWithFilename,
                       atomically: true,
                       encoding: .utf8)

This method erases the existing file and replaces it with the data in question. You do this in a loop, so you're going to overwrite the file many times, always with a single recipe. My expectation is that this would always leave just the last recipe in the file.

I believe what you meant to do is:

// Encode all the recipes, not one at a time.
let encodedData = try JSONEncoder().encode(recipeData)

// Write them. There's no reason to convert to a string
encodedData.write(to: pathWithFilename, options: [.atomic])

As a beginner, this is probably fine. A more professional approach would likely spread this data over multiple files, use a database, or Core Data. But for small projects with only a few data items, writing a single JSON file is fine.

Sign up to request clarification or add additional context in comments.

2 Comments

Okay so here is my updated function that I call right after I call my function to add a new recipe. I still am not getting anything written to my json file. Not sure what I'm doing wrong. imgur.com/a/gGRaF0N
If there is nothing in the file at all, you're likely either writing to the wrong file, or there's an error being thrown that you're not checking, or there is nothing in the data. You should step through the code, line by line, and make sure at each line that it does what you expect it to do (either with a debugger, or by adding print statements).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.