Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using UUID() with json in swift

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?

like image 514
Arnav Motwani Avatar asked Sep 01 '25 20:09

Arnav Motwani


2 Answers

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.

like image 132
vadian Avatar answered Sep 03 '25 23:09

vadian


(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?

like image 43
Ryan Avatar answered Sep 03 '25 21:09

Ryan