在CollectionView中解码时出现JSON解码器错误

时间:2018-12-07 02:46:49

标签: ios json swift collectionview jsondecoder

我正在获取一组URL,并在“集合视图”中对其进行解码。我之前已经成功完成了此操作,但是这次却收到错误消息。

我收到错误:

  

Swift.DecodingError.dataCorrupted(Swift.DecodingError.Context(codingPath:[],debugDescription:“给定的数据不是有效的JSON。”,underlyingError:可选(错误域= NSCocoaErrorDomain代码= 3840,JSON文本未开始带有数组或对象以及允许未设置片段的选项。“ UserInfo = {NSDebugDescription = JSON文本不是以数组或对象开头并且允许不允许设置片段的选项。})))

我要注意的是,如果可能的话,它似乎正在尝试在完成另一个解码之前对其进行解码。我相信这是因为在我运行该应用程序的某些时候,它将在抛出错误之前很好地打印一两个解码数据实例。

这是我的代码:

struct Details: Codable {
    let name: String
    let location: Location
}

struct Location: Codable {
    let address: Address
    let geoCode: Geo
}

struct Geo: Codable {
    let latitude: String
    let longitude: String
}

struct Address: Codable {
    let street: String
    let state: String
    let city: String
    let postalCode: String
    let country: String
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

 let cell = showtimesCollection.dequeueReusableCell(withReuseIdentifier: "timeCell", for: indexPath) as! TimeCell

let theaters = self.theaterIds[indexPath.row]
    let id = theaters
    let apiKey = ""
    let url = URL(string: "http://data.tmsapi.com/v1.1/theatres/\(id)?api_key=\(apiKey)")
    print(url!)
    let request = URLRequest(
        url: url! as URL,
        cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData,
        timeoutInterval: 10 )

    let session = URLSession (
        configuration: URLSessionConfiguration.default,
        delegate: nil,
        delegateQueue: OperationQueue.main
    )

    let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
        if let data = data {
            do { let theater = try JSONDecoder().decode(Details.self, from: data) //error: Swift.DecodingError.dataCorrupted
                print(theater)

            } catch let err {
                print("JSON Error")
        }
    })

    task.resume()

return cell }

数组看起来像这样:

["12345", "23456", "34567", "45678"]

该数组正在正确打印到控制台,因此正在解码的URL。它们与成功运行的控制器的显示方式相同。

JSON如下:

{
"theatreId": "2469",
"name": "Paramount Theatre",
"location": {
    "telephone": "512-472-5470",
    "geoCode": {
        "latitude": "30.2694",
        "longitude": "-97.7419"
    },
    "address": {
        "street": "713 Congress Ave",
        "state": "TX",
        "city": "Austin",
        "country": "USA",
        "postalCode": "78701"
    }
}
}

为什么我会收到此错误?如果我的理论认为它试图太快地加载它们,那么我如何才能等到第一个完成时呢?

编辑:我在JSONDecoder中添加了一个catch块,并且每次调用都随机获得成功的一个错误。每次我运行该应用时,它看起来都与此类似。

JSON Error
JSON Error
JSON Error
JSON Error
Details(name: "Paramount Theatre", location: Film_Bee.ShowtimesView.Location(address: Film_Bee.ShowtimesView.Address(street: "1245 Station Place", state: "TX", city: "Austin", postalCode: "12345", country: "USA"), geoCode: Film_Bee.ShowtimesView.Geo(latitude: "43.12345", longitude: "-44.12345")))
JSON Error

每次获得成功和失败的次数都不同,总是顺序不同。

编辑:我已经解决了问题,并将解决方案作为答案发布了。

另一种解决方案是在每个呼叫之间设置延迟。我该如何实现?

3 个答案:

答案 0 :(得分:0)

您收到此错误,因为您没有收到JSON数据。 不要忘记像下面的代码一样检查HTTP状态

let url = URL(string: "http://data.tmsapi.com/v1.1/theatres/\(2469)?api_key=\(apiKey)")!

URLSession.shared.dataTask(with: url) { (data, response, error) in

    if error == nil, data != nil, let rep = response as? HTTPURLResponse {

        switch rep.statusCode {
        case 200:
            if let theater = try? JSONDecoder().decode(Details.self, from: data!) {
                print(theater)
            }
        default:
            print("Receive HTTP status: \(rep.statusCode)")
            print(String(data: data!, encoding: .utf8))
            print(rep.statusCode)
        }
    } else {
        print(error)
    }
}.resume()

由于该端点,API响应为:

<h1>Not Authorized</h1>

,状态码为 403

答案 1 :(得分:0)

所以我尝试了以下代码:

let data = """
{
    "theatreId": "7719",
    "name": "Navy Pier IMAX Theatre",
    "location": {
        "telephone": "312-595-5629",
        "geoCode": {
            "latitude": "41.8921",
            "longitude": "-87.6088"
        },
        "address": {
            "street": "600 E. Grand Ave. Ste 115",
            "state": "IL",
            "city": "Chicago",
            "country": "USA",
            "postalCode": "60611"
        }
    }
}
""".data(using: .utf8)!
do {
    let theater = try JSONDecoder().decode(Details.self, from: data)
    print("Name: \(theater.name)")
} catch {
    print(error)
}

并且您的代码有效,它给了我以下输出:

  

名称:海军码头IMAX剧院

答案 2 :(得分:0)

问题在于该API每秒仅允许2个调用,而我试图进行更多操作。

要解决此问题,我将不得不使用tmsapi升级我的帐户。