簡體   English   中英

我正在嘗試從 Swift subreddit 解析 JSON。 為什么我有問題?

[英]I am trying to parse JSON from the Swift subreddit. Why am I having issues?

我想知道為什么在使用 Decodable 解析 JSON 時會得到 keyNotFound。

我需要從https://www.reddit.com/r/swift/.json解析 JSON 我需要描述的“selftext”字段以及圖像的“url”。 它們的嵌套方式不同。

到目前為止,這是我的 Reddit 模型:

import Foundation

struct Model : Decodable {
    let data: ListingData
}

struct ListingData: Decodable {
    let children: [Child]
}

struct Child: Decodable {
    let data: ChildData
}

struct ChildData : Decodable {
    let selftext: String
    let preview: ImageURL
}

struct ImageURL: Decodable {
    let url: URL
}

這是我的網絡服務:

import Foundation

class NetworkingService {

    static let shared = NetworkingService()
    private init() {}

    let session = URLSession.shared

    func getReddits(success successBlock: @escaping (ChildData) -> Void) {
        guard let url = URL(string: "https://www.reddit.com/r/swift/.json") else { return }
        let request = URLRequest(url: url)

        session.dataTask(with: request) { [weak self] data, _, error in
            guard self != nil else { return }

            if let error = error { print(error); return }
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase

                let model = try decoder.decode(ChildData.self, from: data!)
                successBlock(model)
            } catch {
                print(error)
            }
            }.resume()
    }
}

我的帶有 collectionView 的 HomeViewController 如下所示:

import UIKit

class HomeViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    @IBOutlet weak var collectionView: UICollectionView!

    private var reddits: [ChildData] = []

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        collectionView.layer.cornerRadius = 0.5
        let nib = UINib(nibName: "RedditsCollectionViewCell", bundle: nil)
        self.collectionView.register(nib, forCellWithReuseIdentifier: "RedditsCollectionViewCell")

        NetworkingService.shared.getReddits { [weak self] (response) in
            self?.reddits = [response]
        }
    }

    override func viewDidAppear(_ animated: Bool) {
    }

    //Number of views
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return reddits.count
    }

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

        if let redditCell = collectionView.dequeueReusableCell(withReuseIdentifier: "RedditCollectionViewCell", for: indexPath) as? RedditCollectionViewCell {

                print("collection1 \(redditCell.isAnimated)")
                redditCell.updateCell(with: reddits[indexPath.row])

            return redditCell
        } else {
            return UICollectionViewCell()
        }
    }
}

extension UICollectionView {
    func reloadData(_ completion: @escaping () -> Void) {
        reloadData()
        DispatchQueue.main.async { completion() }
    }
}

最后,我的 Cell 看起來像這樣:

import UIKit

class RedditCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var redditImage: UIImageView!
    @IBOutlet weak var redditTitleLabel: UILabel!
    @IBOutlet weak var shadowView: UIView!

    @IBOutlet weak var viewCenterConstraint: NSLayoutConstraint!
    @IBOutlet weak var labelCenterConstraint: NSLayoutConstraint!

    func updateCell(with reddit: ChildData) {
    }
}

extension UIImageView {

    func loadImage(from url: URL) {
        URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
            if let error = error {
                print(error)
            }

            guard let data = data else { return }

            let image = UIImage(data: data)
            DispatchQueue.main.async {
                self?.image = image
            }
            }.resume()
    }
}

謝謝!

首先,解碼時需要從你的根結構體Model開始

let model = try decoder.decode(Model.self, from: data!)

那么你的結構聲明是錯誤的,因為 url 部分被進一步嵌套,所以我需要添加一些結構,並且preview似乎並不總是存在,所以我將該屬性設為可選

struct ChildData : Decodable {
   let selftext: String
   let preview: Images?
}

struct Images : Decodable {
    let images: [Source]
}

struct Source : Decodable {
    let source: ImageURL
}
struct ImageURL: Decodable {
    let url: URL
}

我的簡單打印來驗證代碼

let model = try decoder.decode(Model.self, from: data!)
for child in model.data.children {
    if let image = child.data.preview?.images.first {
        print(image.source.url)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM