-2

My apologies if this sounds dumb but where does JSONDecoder get its data from? I keep getting "Grid" and "Red" so I think its just decoding this dummy I set up and not the JSONEncoder().encode(myStarageObject) from the last time the program ran. Here is my code that I've managed from seeing online tutorials and examples:

private func loadMyObject() -> MyObject? {
  let jsonString = """
  {
   "type":"Grid",
    "color":"Red",
    "lineThickness":2
  }
  """
  if let jsonData = jsonString.data(using: .utf8) {
    do {
      let loadedObject = try JSONDecoder().decode(myStorageStruct.self,from: jsonData)
      print("I loaded type \(loadedObject.type) of color: \(loadedObject.color)")
      return makeMyObjectFromStorageData(loadedObject)
      } else {
        return nil
      }
    } catch  let error { print(error) }
  } else {
    return nil
  }
return nil
}
Paul K.
  • 95
  • 1
  • 12
  • 1
    *You* pass the "dummy data" as `from: jsonData` to the decoder ... – Martin R Jan 29 '18 at 20:11
  • 1
    Unrelated, but `jsonString.data(using: .utf8)` will never fail. If you are *forceunwrappophobic* you can write `let jsonData = Data(jsonString.utf8)` – vadian Jan 29 '18 at 20:15
  • Hi Martin R. I realize I am passing dummy data to the decoder as that is all the examples I've seen. What I'm asking is what should I be passing in to get the object I encoded last time I executed the program? – Paul K. Jan 29 '18 at 20:18
  • @PaulK. What are you doing with the data you encoded? Are you saving it in any way (writing to a file, the network, etc.)? Whatever operation you perform to save the data, you'll need to perform the opposite. – Itai Ferber Jan 29 '18 at 20:21
  • I'm trying to save some user preference data from one executing to the next. Back when I was trying to use NSCoding the instructions were to create an ArchiveURL which was used. That made sense to me as it seemed like data was getting written to a file and saved in the file system. But when I asked for some help people told me 'you shouldn't be using NSCoding, use Codable.' And Codable examples encode and decode with JSON but I don't see where the file system is used so I don't know where the object data goes... – Paul K. Jan 29 '18 at 20:27
  • @PaulK. If you're trying to read from/write to files, then you'll need to use [`Data.init(contentsOf:options:)`](https://developer.apple.com/documentation/foundation/data/1779617-init) and [`Data.write(to:options:)`](https://developer.apple.com/documentation/foundation/data/1779858-write) to manually read and write the data produced by `JSONEncoder`/consumed by `JSONDecoder` – Itai Ferber Jan 29 '18 at 21:21
  • `NSKeyedArchiver`/`NSKeyedUnarchiver`'s convenience methods just do that for you, but it's a simple step. – Itai Ferber Jan 29 '18 at 21:21
  • Thanks Itai. Are there any examples you can point to showing Data.write(to:options:) that write a class's variables' data? I'm not sure if you are supposed to write the class object, or the result of JSONEncoder().encode(myObject). On your other comment about NSKeyedArchiver, that sounds like going back to NSCoding and abandoning Codable right? – Paul K. Jan 30 '18 at 15:47

2 Answers2

0

If you're looking to write to files and read from them later, you'll need to manually perform those actions.

To write:

let json: Data
do {
    // encoder is a JSONEncoder
    json = try encoder.encode(someObject)
} catch {
    // Failure to encode. Do something sensible with `error`.
}

do {
    try json.write(to: archiveURL)
} catch {
    // Failure to write to disk. Do something sensible with `error`.
}

To read:

let json: Data
do {
    json = try Data(contentsOf: archiveURL)
} catch {
    // Failure to read from disk. Do something sensible with `error`.
}

// Replace MyType with the actual type.
let someObject: MyType
do {
    // decoder is a JSONDecoder
    someObject = try decoder.decode(MyType.self, from: json)
} catch {
    // Failure to decode. Do something sensible with `error`.
}

You can shorten these examples based on how you plan on handling errors, but this is the gist.

Itai Ferber
  • 28,308
  • 5
  • 77
  • 83
  • Thank you. Unfortunately this write code fails in a way that the first catch doesn't catch so I am unable to tell you why it is failing. Thank you for trying to help and sorry I can't be more informative. I wish I knew how. – Paul K. Jan 30 '18 at 15:28
  • @PaulK. Can you share your exact code for doing this and how it's failing? Is it crashing? Is it producing unexpected data? If you `print(error)` inside the `catch` blocks, is anything printed? The code above as-is can't fail with an error and not catch it, so it's helpful to see exactly what you've got. – Itai Ferber Jan 30 '18 at 15:48
0

For small amounts of data storage I found writing with

let userDefaults = UserDefaults.standard
userDefaults.set(yourTypeVariable,"type")

and reading with

let userDefaults = UserDefaults.standard
let defaultType = userDefaults.string("type")

worked just fine.

Paul K.
  • 95
  • 1
  • 12