Using UUID() with json in swift

4.8k Views Asked by At

I have found examples online that use hardcoded uuids in the json file and the works perfectly for me, however as I am adding the ability to delete items from the json array in my app I need these uuid's to be created dynamically

Here is my json file (list.json), it used to have hard coded ids like "id": 1 and worked (when I used int for ids )

[
  {
    "name": "Dune",
    "author": "Frank Herbert",
    "page": "77"
  },
  {
    "name": "Ready Player One",
    "author": "Ernest Cline",
    "page": "234"
  },
  {
    "name": "Murder on the Orient Express",
    "author": "Agatha Christie",
    "page": "133"
  }
]

Here is my struct (Book.swift)

struct Book: Hashable, Codable, Identifiable {
    var id = UUID()
    var name: String
    var author: String
    var page: String
}

When I decode my json file using this struct with the code (Data.swift)...

let bookData: [Book] = load("list.json")

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find \(filename) in main bundle.")
    }
    
    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

my last fatal error is executed because the id key has no value associated with it (because I removed it in my json file)

How do I initialize my json file with an id so that my id = UUID() statement in my struct can assign it a unique id?

3

There are 3 best solutions below

0
On

Okay so here is my solution. Rather than dynamically filling the id field now, I will fill them when I am using an Encodable function with variable = UUID().uuidstring. Therefore my examples will have hardcoded ids but when people add their own books to my app, my app will generate the id. Its a simple solution but as a beginner I didn't know what to look for.

3
On

(I think I saw your post on Reddit.)

You can create an init for the Book struct that generates a UUID. In fact, you can create several inits for an object that ask for different inputs or give defaults for various parameters depending on how you want the construction logic to run. That can be pretty handy.

You should keep the UUID in your CodableKeys if its an essential part of your data structure.

You may want to consider whether a run-time generated UUID will truly unique your objects as you wish. Do you want multiple objects that share the same title and author? A user could forget they added a particular book. Do you want to use ISBNs or try to unique things yourself, such as detect duplicate or close-to-duplicate titles and ask the user if they really mean to double down on two of the same book?

3
On

In this case you have to specify CodingKeys and omit id

struct Book: Hashable, Codable, Identifiable {
    let id = UUID()
    let name: String
    let author: String
    let page: String

    private enum CodingKeys : String, CodingKey { case name, author, page }
}

Apparently the struct members are not going to be modified so declare them as constants.