1

I am trying to decode data from my realtime database using codable structs in Swift, but am stuck trying to decode a dictionary with an array but I do not know how to make this right. I want the usedBy dictionary decoded but cannot figure out how.

Here is the data in firebase:

{
  "active": 1,
  "code": "FELLA",
  "owner": 33206,
  "percent": 50,
  "usedBy": {
    "-N5lHtnKtAiBWrQMxW0a": {
      "amount": 1000,
      "date": "2022-06-29 21:08:51 +0000",
      "paid": false,
      "userid": 33206
    },
    "-N6L0vybeecuu175FV-4": {
      "amount": 5000,
      "date": "2022-07-07 00:20:41 +0000",
      "paid": false,
      "userid": 33206
    },
    "-N6L0w5WVS6mkVGrfJMW": {
      "amount": 5000,
      "date": "2022-07-07 00:20:41 +0000",
      "paid": false,
      "userid": 33206
    },
    "-N6L190TsMr6OJAXod1G": {
      "amount": 1000,
      "date": "2022-07-07 00:21:38 +0000",
      "paid": false,
      "userid": 33206
    }
  }
}

Data models:

struct PromoCode: Codable {
    var active: Int
    var amount: Int?
    var code: String
    var percent: Int?
    var owner: Int?
    var usedBy: [PromoCodeUsed]?
}

struct PromoCodeUsed: Codable {
    var amount: Int
    var date: String
    var paid: Bool
    var userid: Int
}

Code:

func getPromoCodeInfo(handler: @escaping (PromoCode?) -> ()) {
    guard let userid = AuthService.shared.userID else { return }
    promoCodes.queryOrdered(byChild: "owner").queryEqual(toValue: userid).observeSingleEvent(of: .value) { snapshot in
        
        
        for child in snapshot.children {
            guard let snap = child as? DataSnapshot else { return }
            guard let value = snap.value as? [String: Any] else { return }
            do {
                let jsonData = try JSONSerialization.data(withJSONObject: value, options: [])
                let decoded = try JSONDecoder().decode(PromoCode.self, from: jsonData)
                handler(decoded)
            } catch {
                print("ERROR HERE: \(error)")
            }
        }
    }
}

Error message:

ERROR HERE: typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "usedBy", intValue: nil)], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

How can I fix my this so that I can decode the usedBy dictionary as an array of PromoCodeUsed Objects?

3
  • Does this help? stackoverflow.com/questions/50713638/… Commented Jul 8, 2022 at 2:45
  • @jnpdx unfortunately not, Firebase is different than some APIs in that it doesn't explicitly return arrays, just objects with a list objects Commented Jul 8, 2022 at 2:56
  • Right, but the answer I pointed towards shows that -- the input is an object and then a custom public init(from decoder: Decoder) parses the object into keyed array components. Commented Jul 8, 2022 at 3:10

1 Answer 1

-1

The model you are using is wrong, it should be like this :

struct PromoCode: Codable {
    let active: Int?
    let code: String?
    let owner, percent: Int?
    let usedBy: [String: PromoCodeUsed]?
}


struct PromoCodeUsed: Codable {
    let amount: Int?
    let date: String?
    let paid: Bool?
    let userid: Int?
}

and then need to update getPromoCode function implementation according to that.

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

1 Comment

I do not need the String key though, just the PromoCodeUsed info as an array

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.