0

I have a JSON which has a variable of two different types (same as here).

I used the code which is marked as solution in the linked question and I want to print a variable in a for loop:

struct GetEvents: Decodable{
    var id: String?
    var expansion: String?
    var distance: Distance?
}

enum Distance: Codable {
    case int(Int)
    case string(String)
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .int(let v): try container.encode(v)
        case .string(let v): try container.encode(v)
        }
    }
    
    init(from decoder: Decoder) throws {
        let value = try decoder.singleValueContainer()
        do {
            self = .int(try value.decode(Int.self))
        } catch DecodingError.typeMismatch {
            self = .string(try value.decode(String.self))
        }
    }
    
    enum ParseError: Error {
        case notRecognizedType(Any)
    }
}

I try to print all variables with a for-loop because i have multiple objects inside the object.

for i in 0...(getEventsText.items.count - 1) {
    if let idAsString = getEventsText.items[i].id {
        print(idAsString)
    }
    if let distanceAsString = getEventsText.items[i].distance {
        print(distanceAsString)
    }
    if let epansionAsString = getEventsText.items[i].offer_expansion {
        print(expansionAsString)
    }

I get the id and the expansion but the distance is showing as int(-1) and not as -1

If I just output it like this:

for x in range getEventsText.items {
    print(x)
}

It prints:

GetEvents(id: Optional("7576"), distance: Swift.ImplicitlyUnwrappedOptional<DB_Read_enums_Test1.Distance>.some(DB_Read_enums_Test1.Distance.int(0)), expansion: Optional("0"))
  • 1
    `Distance` is an enum with associated types. You have consider the associated type. And `for i in 0...(getEventsText.items.count - 1) {` is horrible. There is more efficient `for item in getEventsText.items {` – vadian Mar 08 '19 at 11:48
  • Since Swift 4.2, you may use the Codable protocol. It makes encoding and decoding JSON very easy. – Johnny Bueti Mar 08 '19 at 12:51
  • I kinda messed up, I just edited the text – Kühlhausvogel Mar 08 '19 at 13:41

1 Answers1

1

Let Distance implement CustomStringConvertible and add the following

var description: String {
    switch self {
        case let .int(value):
            return "\(value)"
        case let .string(value):            
            return value
    }
}

enum Distance: Codable, CustomStringConvertible {
    case int(Int)
    case string(String)

    var description: String {
        switch self {
        case let .int(value):
            return "\(value)"
        case let .string(value):            
            return value
    }

    //rest of code
}

Test case

let data = """
    {"id": "7576", "expansion": "0", "distance": -1}
    """.data(using: .utf8)!

do {
    let decoder = JSONDecoder()

    let result = try decoder.decode(GetEvents.self, from: data)
    print(String(describing: result.id))
    print(String(describing: result.expansion))
    print(String(describing: result.distance))    
} catch {
    print(error)
}

output is

Optional("7576")
Optional("0")
Optional(-1)

and if I change my json to "..."distance": "long"} then the last output row changes to

Optional(long)
Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52