Свифт JSON не может декодировать.Чередование между String, Int, Bool приводит к различным ошибкам несоответствия типов - PullRequest
0 голосов
/ 02 марта 2019

У меня проблемы с анализом JSON.

URL, который я использую для извлечения этого JSON ниже: https://api.flickr.com/services/rest/?method=flickr.photos.getSizes&api_key=f5963392b48503b5e16b85a3cb31cf31&photo_id=46532317604&format=json&nojsoncallback=1

{
"sizes": {
    "canblog": 0,
    "canprint": 0,
    "candownload": 1,
    "size": [
        {
            "label": "Square",
            "width": 75,
            "height": 75,
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_s.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/sq/",
            "media": "photo"
        },
        {
            "label": "Large Square",
            "width": "150",
            "height": "150",
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_q.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/q/",
            "media": "photo"
        },
        {
            "label": "Thumbnail",
            "width": "100",
            "height": "77",
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_t.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/t/",
            "media": "photo"
        },
        {
            "label": "Small",
            "width": "240",
            "height": "184",
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_m.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/s/",
            "media": "photo"
        },
        {
            "label": "Small 320",
            "width": "320",
            "height": 245,
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_n.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/n/",
            "media": "photo"
        },
        {
            "label": "Medium",
            "width": "500",
            "height": "383",
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/m/",
            "media": "photo"
        },
        {
            "label": "Medium 640",
            "width": "640",
            "height": "490",
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_z.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/z/",
            "media": "photo"
        },
        {
            "label": "Medium 800",
            "width": "800",
            "height": 613,
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_c.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/c/",
            "media": "photo"
        },
        {
            "label": "Large",
            "width": "1024",
            "height": "784",
            "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_b.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/l/",
            "media": "photo"
        },
        {
            "label": "Original",
            "width": "1280",
            "height": "980",
            "source": "https://farm8.staticflickr.com/7896/46532317604_e04977f75e_o.jpg",
            "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/o/",
            "media": "photo"
        }
    ]
},
"stat": "ok"

}

Когда я объявляю переменную height & width как String, я получаюподсказал, что вместо этого был найден номер.Когда я объявляю высоту и ширину как Int или Double, я получаю сообщение, что строка / данные были найдены.В целях тестирования я объявил тип как Высота и Ширина как Bool, я получил ошибку, что вместо этого было найдено число.

Decodable Struct and Compile error for String & Int Types

Меня не волнуетвысота и ширина, и если бы было возможно установить эти переменные в Any или AnyObject и / или отбросить их, я бы принял это.Однако я не нашел ни одного примера типа Any или AnyObject, работающего с Codable Struct.Должен ли я подумать о преобразовании своего кода для использования JSONSerialization?

Мой текущий код приведен ниже:

class func getPhotoSizeWithURL(photoId: String, completion: @escaping (String?, Error?)-> Void){
    let url = Endpoints.getPhotosGetSizes(photoId).url

    let task = URLSession.shared.dataTask(with: url) { (data, response, err) in
        print("\n\n\nGoing to URLSession with --> \(url)")
        if let error = err {
            DispatchQueue.main.async {
                completion(nil, error)
            }
            return
        }

        guard let data = data else {
            DispatchQueue.main.async {
                completion(nil, err)
            }
            return
        }

        do {
            let dataObject = try JSONDecoder().decode(PhotosGetSizes.self, from: data)
            print("GET-SIZES ---> \(dataObject.sizes.size.last?.url ?? "")")

            DispatchQueue.main.async {
                completion(dataObject.sizes.size.first?.url, nil)
            }
            return
        } catch let conversionErr {
            print("\(conversionErr.localizedDescription)\n\n\(conversionErr)")
            DispatchQueue.main.async {
                completion(nil, conversionErr)
            }
            return
        }
    }
    task.resume()
}

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Как видно из JSON, вы указали высоту и ширину, которые иногда возвращаются в виде строк, а иногда возвращаются в виде чисел в API, который вы вызываете:

"size": [
    {
        "label": "Square",
        "width": 75, // <-- number
        "height": 75, // <-- number
        "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_s.jpg",
        "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/sq/",
        "media": "photo"
    },
    {
        "label": "Large Square",
        "width": "150", // <-- string
        "height": "150", // <-- string
        "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_q.jpg",
        "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/q/",
        "media": "photo"
    },
    ...
    {
        "label": "Small 320",
        "width": "320", // <-- string
        "height": 245, // <-- number... really?
        "source": "https://farm8.staticflickr.com/7896/46532317604_61fbd5812b_n.jpg",
        "url": "https://www.flickr.com/photos/72616463@N00/46532317604/sizes/n/",
        "media": "photo"
    },
    ...
]

Конечно, JavaScript - это странный брат, который этого не делаеттак много заботитесь о типах, по крайней мере, по сравнению со шрифтом Swift, который строго типизирован.

Вы говорите, что вам не нужны свойства высоты и ширины, и спрашиваете, есть ли способ отбросить их:

  • Да!Просто оставьте их вне вашего типа Codable, и не будет предпринято никаких попыток десериализации их.

  • Или, молча всхлипывайте, сталкиваясь с реальностью чисел, возвращаемых в виде строк, и создавайте собственный тип Codableдля размеров, которые можно инициализировать из строк или чисел, как предложил Ш_Кхан.

0 голосов
/ 02 марта 2019

Вы можете попробовать enum ширины и высоты для своего текущего ответа, теперь либо String / Int проверьте и добавьте любую другую возможность

struct Root: Codable {
    let sizes: Sizes
    let stat: String
}

struct Sizes: Codable {
    let canblog, canprint, candownload: Int
    let size: [Size]
}

struct Size: Codable {
    let label,media,source: String
    let width, height: Height 
    let url:URL
}

enum Height: Codable {
    case integer(Int)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Height.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Height"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .integer(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...