質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

359閲覧

Swift4 JSONデータをCodableで格納する方法

tomotomo104114

総合スコア15

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2019/03/03 07:31

編集2019/03/06 02:33

????Swift4 JSONデータをCodableで格納する方法

はじめて質問させていただきます。

以下のJSONデータをstrctに格納したいのですが、ネストされたデータを構造体に取得できませんでした。

頂いた回答と参考書を参考にコードを修正した所、nemeのJSONデータは取得できましたが、locationデータを取得できませんでした。

locationの中のデータを格納する際にエラーとなってしまう原因がわかりません。

参考書(たった2日でマスターできるiPhoneアプリ開発集中講座 Xcode 10 Swift 4.2対応 より)

参考書では全体を表す構造は作成していなかったので、今回はその形式を参考にしています。

どうぞよろしくおねがいします。

JSON

1 2[JSONデータ] 3 4{ 5 { 6 "meta": { 7 "code": 200, 8 "requestId": "5c7f2a5b1ed2196e46ea83ef" 9 }, 10 "response": { 11 "venues": [ 12 { 13 "id": "4b792714f964a52018ed2ee3", 14 "name": "東海道新幹線 東京駅", 15 "contact": {}, 16 "location": { 17 "address": "丸の内1-9-1", 18 "lat": 35.681154862661515, 19 "lng": 139.7679060569781, 20 "distance": 71, 21 "postalCode": "100-0005", 22 "cc": "JP", 23 "city": "千代田区", 24 "state": "東京都", 25 "country": "日本", 26 "formattedAddress": [ 27 "丸の内1-9-1", 28 "千代田区, 東京都", 29 "100-0005", 30 "日本" 31 ] 32 }, 33 "categories": [ 34 { 35 "id": "4bf58dd8d48988d129951735", 36 "name": "鉄道駅", 37 "pluralName": "鉄道駅", 38 "shortName": "鉄道駅", 39 "icon": { 40 "prefix": "https://ss3.4sqi.net/img/categories_v2/travel/trainstation_", 41 "suffix": ".png" 42 }, 43 "primary": true 44 } 45 ], 46 "verified": false, 47 "stats": { 48 "tipCount": 0, 49 "usersCount": 0, 50 "checkinsCount": 0, 51 "visitsCount": 0 52 }, 5354 } 55 ], 56 "confident": false 57 } 58}

swift

1[現在のコード] 2 3import UIKit 4import FoursquareAPIClient 5import Social 6 7class SettingViewController: UIViewController, UISearchBarDelegate { //, UITableViewDataSource,UITableViewDelegate { 8 9 override func viewDidLoad() { 10 super.viewDidLoad() 11 12 // Do any additional setup after loading the view. 13 14 searchVenue.delegate = self 15 16 searchVenue.placeholder = "検索スポットの入力" 17 18 // tableView.dataSource = self 19 20 // tableView.delegate = self 21 } 22 23 24 @IBOutlet weak var searchVenue: UISearchBar! 25 @IBOutlet weak var tableView: UITableView! 26 27 //venueListをタプル配列で宣言 必要な部分のみを格納して配列に追加するためにここで宣言 28 var venueList : [(name:String, contact:String, city:String, state : String, country:String)] = [] 29 30 func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { 31 view.endEditing(true) 32 33 if let searchWord = searchBar.text { 34 print(searchWord) 35 } 36 } 37 38 //取得したレスポンスデータ(JSON)を記録する構造体を宣言 39 40 //ItemJson構造体に以下のレスポンスデータを格納 41 struct ItemJson : Codable { //Codable : JSONを変換にした時に、一括して変数にデータを格納するプロトコル 42 let response : JsonResponse 43 } 44 45 struct JsonResponse : Codable { 46 let venues : [JsonVenues] 47 } 48 49 struct JsonVenues : Codable { 50 let name : String? 51 } 52 //↑ここまでは狙い通りの結果 53 54 55 /* ↓ここをコメントアウトすると格納時エラーになります 56 57 //=================================================== 58 59 60 let location : [Jsonlocation] 61 62 } 63 64 struct Jsonlocation : Codable { 65 let city : String? 66 let state : String? 67 let country : String? 68 } 69 //=================================================== 70 71 72 */ 73 74 75 struct ResultJson : Codable { 76 let item : [ItemJson]? 77 } 78 79 80 //現在位置ボタンタップ時リクエストURL作成 81 @IBAction func searchNearVenue(_ sender: Any) { 82 83 84 //認証KeyであるIDとSecretの宣言 85 let clientId = "*****" 86 let clientSecret = "*****" 87 88 // 現在位置を東京駅に指定 89 // to do GPSから現在位置を取得する 90 let currentLocation_latitude = 35.681236 91 let currentLocation_longitude = 139.767125 92 93 //緯度経度からvenue検索するreq_URL作成。検索数、範囲を指定。 94 95 96 guard let req_url = URL (string : "https://api.foursquare.com/v2/venues/search?v=20180228&ll=(currentLocation_latitude),(currentLocation_longitude)&intent=checkin&limit=1&radius=4000&client_id=(clientId)&client_secret=(clientSecret)") 97 else { 98 return 99 } 100 101 //req_URLのデバック 102 print(req_url) 103 104 //以下で、req_urlにアクセスし構造体にレスポンスデータを格納する処理を行う 105 106 //req_urlをロードするプロトコルを宣言 107 let req = URLRequest(url: req_url) 108 109 let session = URLSession(configuration: .default, delegate: nil, delegateQueue: OperationQueue.main) 110 111 //ダウンロード先URL:req、data格納、通信状態データ格納、エラー内容格納 112 let task = session.dataTask(with: req, completionHandler: { 113 (data, response, error) in 114 115 session.finishTasksAndInvalidate() 116 117 // パースの際にエラーになった場合の例外処理でdo catch 118 do { 119 120 //JSONをデコードするためのオブジェクトを作成 121 let decoder = JSONDecoder() 122 123 //受け取ったJSONデータをパースして格納 124 125 //↓decode(***)が鍵である 126 //ResultJsonだとエラーItemJsonにしたらなぜか上手くいった 127 128 129 let json = try decoder.decode(ItemJson.self, from: data!) 130 131 //デバック用 132 print (json) 133 134 135 } catch { 136 137 print("エラーが発生しました") 138 139 } 140 141 }) 142 143 task.resume() 144 145 } 146 147 148 149} //end 150

JSON

1 2参考書が使っているJSONデータ 3 4{ 5 "item": [ 6 { 7 "id": "6833", 8 "name": "ベビースターチップス(CoCo壱番屋カツカレー味)", 9 "kana": "べびーすたーちっぷすここいちばんやかつかれーあじ", 10 "maker": "おやつカンパニー", 11 "price": "128", 12 "type": "snack", 13 "regist": "2010年7月2日", 14 "url": "略/", 15 "tags": { 16 "tag": [ 17 "カレー", 18 "コラボ", 19 "ベビースター", 20 "季節限定" 21 ] 22 }, 23 "image": "http://www.sysbird.jp/toriko/wp-content/blogs.dir/2/files/6833.gif", 24 "comment": "<p>略</p>\n" 25//以下略 26 }, 27 </p>\n" 28 } 29 ], 30 "status": "OK", 31 "count": "2" 32}

swift

1 2参考書のコード 3 4 //Jsonのitem内のデータ構造 5 struct ItemJson: Codable { 6 //お菓子の名前 7 let name: String? 8 //メーカー 9 let maker: String? 10 //掲載URL 11 let url: URL? 12 //画像のURL 13 let image: URL? 14 } 15 16 //JSONのデータ構造 17 struct ResultJson: Codable { 18 //複数要素 19 let item:[ItemJson]? 20 } 21 22 //searchokashiメソッド 23 func searchOkashi (keyword: String) { 24 25 //お菓子の検索キーワードをURLエンコードする 26 guard let keyword_encode = keyword.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { 27 return 28 } 29 30 //リクエストURLの組み立て 31 guard let req_url = URL(string: 32 "http://www.sysbird.jp/toriko/api/?apikey=guest&format=json&keyword=(keyword_encode)&max=10&prder=r") else { 33 return 34 } 35 print(req_url) 36 37 //リクエストに必要な情報を生成 38 let req = URLRequest(url: req_url) 39 //データ転送を管理するためのセッションを生成 40 let session = URLSession(configuration: .default, delegate: nil, delegateQueue: OperationQueue.main) 41 //リクエストをタスクとして登録 42 let task = session.dataTask(with: req, completionHandler: { 43 (data, response, error) in 44 //セッション終了 45 session.finishTasksAndInvalidate() 46 //do try catcyエラーハンドリング 47 do{ 48 //JSONDecoderのインスタンス取得 49 let decoder = JSONDecoder() 50 //受け取ったJSONデータをパース(解析)して格納 51 let json = try decoder.decode(ResultJson.self, from:data!) 52 53 54 //お菓子の情報が取得できているか確認 55 if let items = json.item { 56 //お菓子のリストを初期化 57 self.okashiList.removeAll() 58 //取得したお菓子の数だけ処理 59 for item in items { 60 //お菓子の名前、メーカ名、掲載URL,画像URLをアンラップ 61 if let name = item.name, let maker = item.maker, let link = item.url, let image = item.image { 62 //1つのお菓子をタプルでまとめて管理 63 let okashi = (name, maker, link, image) 64 //お菓子の配列へ追加 65 self.okashiList.append(okashi) 66 } 67 } 68 //TableView を更新する 69 self.tableView.reloadData() 70 if let okashidbg = self.okashiList.first { 71 print ("-----------------") 72 print ("okashiList[0] = (okashidbg)") 73 } 74 } 75 76 } catch { 77 //エラー処理 78 print("エラーが出ました") 79 } 80 }) 81 //ダウンロード開始 82 task.resume() 83 } 84//以下略 85 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

JSONDecoderはJSONの一部だけをデコードすることは出来ません。
JSON全体を表すstructを作ってください。

投稿2019/03/03 10:21

MasakiHori

総合スコア3384

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tomotomo104114

2019/03/04 21:57 編集

お返事ありがとうございます! 以下のようにresponse全体を表すstruct構造を試してみましたが、格納する際にエラーとなりました。 どこが間違ってしまったのでしょうか?どうぞよろしくお願いします。 struct ItemJson : Codable { var response : ItemJsonResponse struct ItemJsonResponse : Codable { var venues : [ItemJsonVenues] } struct ItemJsonVenues : Codable { let name : String? let city : String? let state : String? let country : String? } } struct ResultJson : Codable { let response : [ItemJson]? }
MasakiHori

2019/03/05 01:13

metaがありません。 responseは配列ではありません。 categoriesがありません。 全体を表すstructを作ってください。
tomotomo104114

2019/03/06 02:40 編集

MasakiHori様 度々質問をしてしまい申し訳ございませんが、質問を編集致しましたのでお時間のある時に確認していただけると幸いです。 現在nameの格納はできましたが、その他のデータが格納できません。 参考書では全体を表すstructを作成していなかったので、必要な部分のみ正確にstructできれば良いのかな?と思いコードを修正しました。 今回はたまたまnameは取得できたましたが、MasakiHoriさんのおっしゃるように全体structを作成していないことでlocation内のデータが取得できなかったのかなとも思っています 。
guest

0

自己解決

自己解決しました
JSONデータの表記方法を調べて理解したら簡単な話でした。

swift

1 2 //ItemJson構造体に以下のレスポンスデータを格納 3 struct ItemJson : Codable { 4 let response : JsonResponse 5 } 6 7 struct JsonResponse : Codable { 8 let venues : [JsonVenues] 9 } 10 11 struct JsonVenues : Codable { 12 let name : String? 13 14 //JSONデータがオブジェクトだったのに配列で宣言していたので格納エラーになっていた 15 let location : Jsonlocation 16 } 17 18 struct Jsonlocation : Codable { 19 let city : String? 20 let state : String? 21 let country : String? 22 } 23 24 // structの配列化 25 struct ResultJson : Codable { 26 let item : [ItemJson]? 27 } 28

投稿2019/03/07 12:58

tomotomo104114

総合スコア15

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問