swiftを学習して2週間、初学者です。
apiのレスポンスJSONをCodableで読み取りができないエラーに差し掛かっています。
エラー内容
typeMismatch(Swift.Array<Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array<Any> but found a dictionary instead.", underlyingError: nil))
導入したAPIはRakuten RapidAPIのJokesというAPIを導入しています。
JSONテストで返ってくる値は
{2 items "success":{1 item "total":4 } "contents":{2 items "categories":[4 items 0:{4 items "language":"en" "name":"jod" "background":"" "description":"Joke of the day " } 1:{4 items "language":"en" "name":"animal" "background":"" "description":"Animal Joke of the day " } 2:{4 items "language":"en" "name":"blonde" "background":"" "description":"Blonde joke of the day!" } 3:{4 items "language":"en" "name":"knock-knock" "background":"" "description":"Knock Knock joke of the day!" } ] "copyright":"2019-20 https://jokes.one" } }
この値のdescriptionのみ取得したいと考えています。
該当コード
import UIKit import Foundation struct Jokes: Codable { let contents: Contents enum CodingKeys: String, CodingKey { case contents = "contents" } } struct Contents: Codable { let categories: Categories enum CodingKeys: String, CodingKey { case categories = "categories" } } struct Categories: Codable { let description: String enum CodingKeys: String, CodingKey { case description = "description" } } class JokesViewController: UIViewController { private let cellId = "cellId" private var jokes = [Jokes]() let tableView: UITableView = { let tv = UITableView() return tv }() override func viewDidLoad() { super.viewDidLoad() view.addSubview(tableView) tableView.frame.size = view.frame.size tableView.backgroundColor = .black tableView.separatorColor = .lightGray tableView.separatorInset.left = 0 navigationItem.title = "元気がでる一言" tableView.delegate = self tableView.dataSource = self tableView.register( UITableViewCell.self, forCellReuseIdentifier: cellId) let headers = [ "x-rapidapi-key": "非表示にしてる", "x-rapidapi-host": "非表示にしてる" ] let request = NSMutableURLRequest(url: NSURL(string: "https://jokes.p.rapidapi.com/jod/categories")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in if (error != nil) { print("error: ",error) } else { let httpResponse = response as? HTTPURLResponse print("httpResponse: ",httpResponse) } if let data = data { do { let joke = try JSONDecoder().decode([Jokes].self, from: data) self.jokes = joke DispatchQueue.main.async { self.tableView.reloadData() } print("json: ", joke) } catch(let error) { print("情報の取得に失敗しました。:", error) } } }) dataTask.resume() } } extension JokesViewController: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 180 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return jokes.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cellId") print("jokes: " ,jokes) // cell.textLabel?.text = jokes[indexPath.row] .description cell.textLabel?.textColor = .white cell.textLabel?.numberOfLines = 0 cell.backgroundColor = .black cell.selectionStyle = UITableViewCell.SelectionStyle.none cell.translatesAutoresizingMaskIntoConstraints = false return cell } }
上記のコードで実装を行っています。
実際に試したこと
レスポンスの取得の際に下記の書き方が悪いのかと思い、[]をなくしてみたり、
if let data = data { do { let joke = try JSONDecoder().decode([Jokes].self, from: data) self.jokes = joke DispatchQueue.main.async { self.tableView.reloadData() } print("json: ", joke) } catch(let error) { print("情報の取得に失敗しました。:", error) } }
Codableの部分に
struct Jokes: Codable { let contents: Contents enum CodingKeys: String, CodingKey { case contents = "contents" } } struct Contents: Codable { let categories: Categories enum CodingKeys: String, CodingKey { case categories = "categories" } } struct Categories: Codable { let description: String enum CodingKeys: String, CodingKey { case description = "description" } }
?を入れたりして実装を行いましたが、一向にJSONをCodableで読み取りたいができませんでした。
もしお手すかれましたら、ご返信いただけましたら幸いです。
何卒宜しくお願いします。
自身での修正箇所
Codableの部分がネストしていることを見落としており、修正を加えました。
struct Jokes: Codable { let contents: [Contents] struct Contents: Codable { let categories: [Categories] struct Categories: Codable { let description: String } } }
修正を加えたのですが、しかしながら現状は情報を取得まで至っていません????
あなたの回答
tips
プレビュー