-1

A few months back I started learning how to use the new codable and I posted this question Swift 4 decoding json using Codable. Right now I'm trying to use Realm and I've changed the model to follow the documents but I keep getting the error that it doesn't conform to decodable. I'm pretty lost as to how to make this work.

{
    "success": true,
    "message": "got the locations!",
    "data": {
        "LocationList": [
         {
            "LocID": 1,
            "LocName": "Downtown"
         },
         {
            "LocID": 2,
            "LocName": "Uptown"
         },
         {
            "LocID": 3,
            "LocName": "Midtown"
         }
      ]
   }
}

class Location: Object, Decodable {
    @objc dynamic var success: Bool = true
    let data = List<LocationData>()
}

class LocationData: Object, Decodable {
    let LocationList = List<LocationItem>()
}

class LocationItem: Object, Decodable {
    @objc dynamic var LocID: Int!
    @objc dynamic var LocName: String!
}
Misha
  • 128
  • 1
  • 12

1 Answers1

1

Instead of declaring your lists like this:

let data = List<LocationData>()
let LocationList = List<LocationItem>()

Declare them like this instead:

var data = LocationData()
var LocationList = [LocationItem]()

This confirms to the codable/decodable

Update:
I made a test which worked out with your models, tryout this:

struct Location: Decodable {
    let success: Bool
    let message: String
    var data = LocationData()
}

struct LocationData: Decodable {
    var LocationList = [LocationItem]()
}

struct LocationItem: Decodable {
    var LocID: Int
    var LocName: String
}

let json = "{ \"success\": true, \"message\": \"got the locations!\", \"data\": { \"LocationList\": [ { \"LocID\": 1, \"LocName\": \"Downtown\" }, { \"LocID\": 2, \"LocName\": \"Uptown\" }, { \"LocID\": 3, \"LocName\": \"Midtown\" } ] } }"


do {
    let data = Data(json.utf8)
    let decoded = try JSONDecoder().decode(Location.self, from: data)
    print(decoded)
} catch let error {
    print(error)
}

This will output:

Location(success: true, message: "got the locations!", data: CodableDecodable.LocationData(LocationList: [CodableDecodable.LocationItem(LocID: 1, LocName: "Downtown"), CodableDecodable.LocationItem(LocID: 2, LocName: "Uptown"), CodableDecodable.LocationItem(LocID: 3, LocName: "Midtown")]))

In your case your models should be:

class Location: Object, Decodable {
    @objc dynamic var success: Bool = true
    var data = LocationData()
}

class LocationData: Object, Decodable {
    var LocationList = [LocationItem]()
}

class LocationItem: Object, Decodable {
    @objc dynamic var LocID: Int!
    @objc dynamic var LocName: String!
}
Rashwan L
  • 38,237
  • 7
  • 103
  • 107
  • Yeah I tried that and I get a typeMismatch error "Expected to decode Array but found a dictionary instead." – Misha Jan 27 '18 at 05:45
  • It´s because your `data` in your JSON is a dictionary. Check the updated answer of how to solve that. – Rashwan L Jan 27 '18 at 05:48
  • The mismatch seems to be from let locations = try JSONDecoder().decode([Location].self, from: data), if i change it to let locations = try JSONDecoder().decode(Location.self, from: data) I'm able to save only a success variable but not any of the actual location data. I updated the the question to add the success. – Misha Jan 27 '18 at 05:58
  • @RashwanL `let data = LocationData()` and `let LocationList = [LocationItem]()` won't work. – Bilal Jan 27 '18 at 06:27
  • @Misha, checkout the update which will help you solve your issue. – Rashwan L Jan 27 '18 at 06:33
  • @Bilal, sure that was a part of OPs issue. – Rashwan L Jan 27 '18 at 06:33
  • I've tried that and I get add explicit '@objc' to the declaration to emit the Objective-C entrypoint in Swift 4 and suppress this message. So I add that to it and then I get "Terminating app due to uncaught exception 'RLMException', reason: 'The `Location.data` property must be marked as being optional" but it won't let me. Your test is how I used to have it with structs, but adding Realm isn't playing nice. – Misha Jan 27 '18 at 06:52
  • I haven't worked with Codable and Realm together yet, but checkout if [this](https://stackoverflow.com/questions/47080785/swift-4-codable-realm-object-subclasses/47194228) helps you. – Rashwan L Jan 27 '18 at 06:56
  • @Misha, did you find any solution for your issue? – Rashwan L Feb 09 '18 at 21:17
  • @RashwanL No I couldn't get the entire model to use realm. I ended up just adding the last model as a realm class and the first two I kept as structs. So I'm just caching LocationItem. – Misha Feb 10 '18 at 00:45
  • 1
    I ended up doing some tests and came up with a similar solution. Great that it worked out for you. – Rashwan L Feb 10 '18 at 09:01