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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

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

Q&A

解決済

1回答

734閲覧

JSONで取得した辞書型のデータをfor文を使用して配列に保存したい

Ka_ya_

総合スコア31

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Xcode

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

Swift

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

0グッド

0クリップ

投稿2020/05/12 03:52

質問失礼します。

JSONでデータを辞書型として取得する事は出来たので、
データの数だけfor文を回して全てのデータを配列に追加し、
一覧表示させる為のデータを作成したいです。

printをしてどういったデータが返ってくるか下記コードの様に試しながら調べていたのですが、
Value of type 'Dictionary<String, Any>.Element' (aka '(key: String, value: Any)') has no subscripts
というエラーが表示されてしまいます。

Swift

1 session.dataTask(with: request) { (data, response, error) in 2 3 if error == nil, let data = data, let response = response { 4//データを取得する 5 let jsonData = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: [String:Any]] 6 print(jsonData) ←コンソールに①の形式で表示される 7//hitsの中身を全て取得したい 8 let dicData:[String:Any] = jsonData["hits"] ?? ["":""] 9 print(productsData) ←コンソールに②の形式で表示される 10//取得した中身の数だけ各項目の値を取得したい 11 for data in dicData{ 12 print(data) ←コンソールに③の形式で表示される 13 let data1 = poroduct["data1"]←上記エラーが表示される 14 }

JSON

12["hits": ["data1": いち, "data2":, "data3":さん]] 34["data1": いち, "data2":, "data3": さん] 56(key: "data1", value: いち) 7(key: "data2", value: に) 8(key: "data3", value: さん)

勉強不足で申し訳ないのですが、
(key: "data1", value: いち)と["data1":いち]で表示される際の辞書型の違いが分かりません。

また、「hits」というkeyで複数件ヒットした際、

["hits": ["data1": いち, "data2": に, "data3":さん],["data4"]:よん, "data5": ご, "data6":ろく]]

の様にデータを受け取ると思うのですが、そうやってデータが入り組んでいる場合にどう取得すれば良いのでしょうか。

辞書型の型変換で何故エラーになるのかや、どう変換すればいいのかが調べても分からずにいます。
どなたかご教授いただけますと嬉しいです。
よろしくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

実行結果を見ていただければわかりますが、(3)はタプルの形になっていますから、タプルとして取り出す必要があります。

③ (key: "data1", value: いち) (key: "data2", value: に) (key: "data3", value: さん)

たとえば、下記のような感じです(ダウンキャストは必要に応じて施して頂けますでしょうか)。

swift

1let data1 = data.value

辞書からの値の取得ですが、たぶん難しく考えすぎていらっしゃるのではないでしょうか。
JSONのデータから hits をキーに取得されている処理は行われているので、同じように考えれば大丈夫です。

swift

1/ JSON の代わり 2let jsonData = ["hits": ["data1": "いち", "data2": "に", "data3":"さん"]] 3print(jsonData) //←コンソールに①の形式で表示される 4 5//hitsの中身を全て取得したい 6let productsData:[String:Any] = jsonData["hits"] ?? ["":""] 7print(productsData) //←コンソールに②の形式で表示される 8 9//取得した中身の数だけ各項目の値を取得したい 10let data1 = productsData["data1"] 11let data2 = productsData["data2"] 12let data3 = productsData["data3"] 13print(data1) 14print(data2) 15print(data3)

気をつけなければいけないのは、辞書から得られる値は Optional 型という点です(キーに相当する値がない場合 nil を返す)。


あるいは、Swift4 以降であれば Codable を使うという手もあります。
こちらはあらかじめ Codable に準拠した構造体を作っておく必要がありますが、取得する JSON の構造が決まっているのであれば、プロパティ名でアクセスできるため取扱い(特に、JSONからのデコード)が容易になります。

swift

1let data = """ 2{ 3 "hits" : { 4 "data1": "いち", 5 "data2": "に", 6 "data3": "さん" 7 } 8} 9""".data(using: .utf8)! 10 11struct jsonStruct: Codable { 12 var hits: Hits 13} 14 15struct Hits: Codable { 16 var data1: String 17 var data2: String 18 var data3: String 19} 20 21// この一行で終わり 22let item = try! JSONDecoder().decode(jsonStruct.self, from: data) 23 24let data1 = item.hits.data1 25let data2 = item.hits.data2 26let data3 = item.hits.data3 27print(data1) 28print(data2) 29print(data3)

投稿2020/05/12 04:12

編集2020/05/12 11:21
TsukubaDepot

総合スコア5086

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

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

Ka_ya_

2020/05/12 04:40

TsukubaDepotさん、ご回答ありがとうございます。 辞書型でなくタプルになってしまっていたんですね…!! 教えていただいた通りにコードを書き換えてみると、 (key: "data1", value: いち) いち (key: "data2", value: に) に (key: "data3", value: さん) さん の様に取得する事はできたのですが、上記の 「いち」 というStringだけを単独で取得するにはどうすれば良いのでしょうか。 調べながら手探り状態でエラーを回避しながらコードを記載していた為、 コードが根本的におかしい可能性もあり申し訳ないのですが、 もしもっと一般的な方法で上記の「いち」のみを取得出来るのであれば、 そういった方法のヒントをいただけるととても助かります。 いつもお手数をおかけして申し訳ないのですが、 よろしければ御教授お願い致します。
Ka_ya_

2020/05/12 12:48

TsukubaDepotさん、何度もすみません>< いつも親切にご回答いただき本当にありがとうございます。 おっしゃる通りエラーに悩みながら色々と記載しているうちに深みにハマっていたので、 丁寧に分かりやすく説明していただけてとても助かります;; 教えていただいた方法で記載をしてみたところ、無事に値を取得する事が出来ました。 Codableを利用する方法も試してみると、コードが簡潔になり凄く感動しました…!! 更に理解を深めたいのでもし可能でしたら教えていただきたいのですが、 JSONのhitsしたデータが複数ある場合、 ["hits": ["data1": "いち", "data2": "に", "data3":"さん"],["data4"]:よん, "data5": ご, "data6":ろく]] となる可能性を踏まえて、下記の質問URLに記載があるコードの様な事をしようと試みていたのですが、 let data = jsonData["hits"] as! [[String:Any]] などの形式を試そうとしても下記のようなエラーが発生するか、値がタプル型になってしまうかで上手くいきませんでした。 (ここから深みにハマってしまいました><) https://teratail.com/questions/54841?link=qa_related_pc 主なエラー内容 ・Value of protocol type 'Any' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols ・Cannot convert sequence element type 'Dictionary<String, Any>.Element' (aka '(key: String, value: Any)') to expected type '[String : Any]' ・Could not cast value of type '__NSDictionaryI' (0x1d965a328) to 'NSArray' 辞書型から配列やタプルには変換できませんというエラー内容だとは思うのですが、 そういった場合にはどう記載を変えれば型変換が行えるのかが分かりませんでした。 すでにコードとしては教えていただいた内容で解決しているのですが、 出来る事ならばダウンキャストについてキチンと理解しておきたいと思っております。 何度もお手数をおかけして本当に申し訳ないのですが、お時間があればで構いませんので、 こちらの内容に関してもヒントをいただけますととても助かります。 丁寧に説明して下さっているのに私の理解力が追いついておらず申し訳ありません。 よろしければお願い致します。
TsukubaDepot

2020/05/12 13:08

> ・Value of protocol type 'Any' cannot conform to 'Sequence'; only struct/enum/class types can conform to protocols > ・Cannot convert sequence element type 'Dictionary<String, Any>.Element' (aka '(key: String, value: Any)') to expected type '[String : Any]' > ・Could not cast value of type '__NSDictionaryI' (0x1d965a328) to 'NSArray' 上記のようなエラーが出るコードを試してみたいのですが、様々な可能性があるためなんとも再現できない状態です。 正確なコメント(対処法)を得るためには、新たに質問を立ち上げていただいた方が確実かと思いますがいかがでしょうか。 ちなみに、ダウンキャストを含むキャスト操作は、継承関係にあるクラス間の変換やAny型を特定の型に変換する目的でのみ用いることが可能です。 たとえば、辞書と配列は共に構造体であり、継承関係もない(構造体なのでそもそも継承という概念がない)ため相互にキャストすることはできません。
TsukubaDepot

2020/05/12 13:35

tyobigorouさん CLIで使えるツールはいいですね。 私は中華圏産のアプリを使っていますが、生成される構造体はそのままでは使えないのでちょっと難儀しているところでした。 試してみます。
Ka_ya_

2020/05/13 02:22

TsukubaDepotさん、丁寧にご教授下さりありがとうございます。 何度もお手数をおかけしてすみません、構造体同士はキャストが出来ないと知ってスッキリしました! エラー名で検索しても英語ばかりヒットしてしまい、 自動翻訳しても説明が理解出来なかったので分かりやすく教えていただけてとても助かりました^^ また詳細に関して疑問点が出てきた際は新たに質問させていただこうと思います。 tyobigorouさん、いつもご回答ありがとうございます。 お陰様で先日まで作成していたアプリは無事に完成いたしました^^ こんな便利なアプリがあるんですね…!! これなら私でもエラーを出さずに記載出来そうなので、 こういったツールを試していこうと思います。 理解力や質問力が足りずお手数をおかけしましたが、とても勉強になりました! 頭がこんがらがってハマっていたので、教えていただける環境が本当にありがたいです。 お二人ともご回答下さりありがとうございました^^
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問