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

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

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

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

Swift

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

0回答

1357閲覧

Swift5 楽天GORAゴルフ場検索APIを使ったアプリを作りたい。

urota

総合スコア0

TableView

TableView(UITableView)とは、リスト形式で表示するコントロールで、ほとんどのアプリに使用されています。画面を「行」に分けて管理し、一般的には各行をタップした際に詳細画面に移動します。

Swift

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2021/05/27 15:48

編集2021/05/28 15:19

前提・実現したいこと

Swift5で楽天GORAゴルフ場検索APIを使ったアプリを作りたい。

発生している問題・エラーメッセージ

テキストフィールドに検索キーワードを入れて検索した際にAPIから取ってきたゴルフ場情報を
テーブルに表示されたいが、テキストフィールドに検索キーワードを入れて検索しても、
テーブルに何も表示されない。

テキストフィールドに検索キーワードを入れて検索した際に、
デバックエリアに表示されているメッセージ

GolfSearchApp[6331:249795] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed

該当のソースコード

Swift5

1import UIKit 2import SafariServices 3 4class ViewController: UIViewController,UISearchBarDelegate,UITableViewDataSource,UITableViewDelegate, SFSafariViewControllerDelegate { 5 6 override func viewDidLoad() { 7 super.viewDidLoad() 8 // Do any additional setup after loading the view. 9 10 //search Barのdelegate通知先を設定 11 searchText.delegate = self 12 13 //ブレースホルダー(searchText欄に表示される)を設定 14 searchText.placeholder = "ゴルフ場の名前を入力" 15 16 //TableViewのdataSourceを設定 17 tableView.dataSource = self 18 19 //TableViewのdelegateを設定 20 tableView.delegate = self 21 22 } 23 24 //story boardのsearch barと紐付け 25 @IBOutlet weak var searchText: UISearchBar! 26 27 //story boardのTableViewと紐付け 28 @IBOutlet weak var tableView: UITableView! 29 30 //ゴルフのリスト(タプル配列) 31 var golfiList : [(golfCourseName:String ,golfCourseCaption:String , golfCourseDetailUrl:URL , golfCourseImageUrl:URL)] = [] 32 33 //検索ボタンを押下時の実行ファンクション 34 func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { 35 36 //キーボードを閉じる 37 view.endEditing(true) 38 39 //入力されたテキストを取り出す 40 if let searchWord = searchBar.text { 41 42 //入力されていたら(nilでない場合)ゴルフ場を検索 43 searchGolf(keyword: searchWord) 44 45 } 46 47 } 48 49 //JSONのitem内のデータを構造 50 struct ItemJson: Codable { 51 52 //ゴルフ場の名称 53 let golfCourseName: String? 54 55 //メーカー 56 let golfCourseCaption: String? 57 58 //掲載URL 59 let golfCourseDetailUrl: URL? 60 61 //画像URL 62 let golfCourseImageUrl: URL? 63 64 } 65 66 //JSONのデータ構造 67 struct ResultJson: Codable { 68 69 //複数要素 70 let item:[ItemJson]? 71 72 } 73 74 //searchOkashiファンクション 75 //第一引数:keyword 検索したいワード 76 func searchGolf(keyword : String) { 77 78 //ゴルフ場の検索キーワードをAPIが認識できるようURLにエンコードする 79 guard let keyword_encode = keyword.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) 80 81 else { 82 83 return 84 85 } 86 87 //リクエストURLの組み立て 88 guard let req_url = URL(string: "https://app.rakuten.co.jp/services/api/Gora/GoraGolfCourseSearch/20170623?format=json&keyword=(keyword_encode)&applicationId=(省略)") 89 90 else { 91 92 return 93 94 } 95 96 print(req_url) 97 98 //リクエストに必要な情報を生成 99 let req = URLRequest(url: req_url) 100 101 //データ転送を管理するためのセッションを生成 102 let session = URLSession(configuration: .default, delegate: nil,delegateQueue: OperationQueue.main) 103 104 //リクエストタスクとして登録 105 let task = session.dataTask(with: req, completionHandler: { 106 107 (data , respons , error) in 108 109 //セッションを終了 110 session.finishTasksAndInvalidate() 111 112 //do try catch エラーハンドリング 113 do { 114 115 //JSONDecoderのインスタンス取得 116 let decoder = JSONDecoder() 117 118 //受け取ったJSONデータをパース(解析)して格納 119 let json = try decoder.decode(ResultJson.self, from: data!) 120 121 //ゴルフ場の情報が取得出来ているか確認 122 if let items = json.item { 123 124 //ゴルフ場のリストを初期化 125 self.golfiList.removeAll() 126 127 //取得しているゴルフ場の数だけ処理 128 for item in items { 129 130 //ゴルフ場の名称、説明文、掲載URL、画像URLをアンラップ 131 if let golfCourseName = item.golfCourseName, let golfCourseCaption = item.golfCourseCaption , let golfCourseDetailUrl = item.golfCourseDetailUrl , let golfCourseImageUrl = item.golfCourseImageUrl { 132 133 //1つのゴルフ場をタプルでまとめて管理 134 let golf = (golfCourseName,golfCourseCaption,golfCourseDetailUrl,golfCourseImageUrl) 135 136 //ゴルフ場の配列へ追加 137 self.golfiList.append(golf) 138 139 } 140 141 } 142 143 //Table Viewを更新する 144 self.tableView.reloadData() 145 146 if let golfdbg = self.golfiList.first { 147 148 print ("----------------") 149 print ("golfiList[0] = (golfdbg)") 150 151 } 152 153 } 154 155 } catch { 156 157 //エラー処理 158 print("エラーが出ました") 159 160 } 161 162 }) 163 164 //ダウンロード開始 165 task.resume() 166 167 } 168 169 //セルの個数を設定するファンクション 170 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 171 172 //検索にヒットした分だけセルを生成したいので、ゴルフリストのカウントで指定。 173 return golfiList.count 174 175 } 176 177 //セルの値を設定するファンクション 178 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 179 180 //今回表示を行うCellオブジェクト(1行)を取得する 181 let cell = tableView.dequeueReusableCell(withIdentifier: "okashiCell") 182 183 //ゴルフ場のタイトル設定 184 cell?.textLabel?.text = golfiList[indexPath.row].golfCourseName 185 186 //ゴルフ場画像を取得 187 if let imageData = try? Data(contentsOf: golfiList[indexPath.row].golfCourseImageUrl) { 188 189 //正常に取得できた場合は、UIImageで画像オブジェクトを生成して、セルにゴルフ場画像を設定 190 cell?.imageView?.image = UIImage(data: imageData) 191 192 } 193 194 //設定済みのCellオブジェクトを画面に反映 195 return cell! 196 197 } 198 199 func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 200 201 //ハイライト解除 202 tableView.deselectRow(at: indexPath, animated: true) 203 204 //SFSafariViewを開く 205 let safariViewController = SFSafariViewController(url: golfiList[indexPath.row].golfCourseDetailUrl) 206 207 //delegateの通知先を自分自身に 208 safariViewController.delegate = self 209 210 //SafariViewが開かれる 211 present(safariViewController, animated: true, completion: nil) 212 213 } 214 215 //SafariViewが閉じられた時に呼ばれるdelegateメソッド 216 func safariViewControllerDidFinish(_ controller: SFSafariViewController) { 217 218 //SafariViewを閉じる 219 dismiss(animated: true, completion: nil) 220 221 } 222 223} 224 225

試したこと

デバックを貼ったところ、
if let items = json.item {
でとまってしまったので、このコードのどこかに問題があるように思います。

補足情報(FW/ツールのバージョンなど)

Xcode
Version 12.4

使用しているAPIのサイト
https://webservice.rakuten.co.jp/api/goragolfcoursesearch/

テキストフィールドに「東京」と入力して検索した時のレスポンスJSONは下記のとおりです。
{
"count": 86,
"page": 1,
"first": 1,
"last": 30,
"hits": 30,
"carrier": 0,
"pageCount": 3,
"Items": [
{
"Item": {
"golfCourseId": 80004,
"golfCourseName": "アジア取手カントリー倶楽部",
"golfCourseAbbr": "アジア取手CC",
"golfCourseNameKana": "あじあとりでかんとりーくらぶ",
"golfCourseCaption": "常磐道の谷和原I.C.より15分!都心からのアクセスの良さが魅力。姉妹コースに続き、【セグウェイ】を100台導入!日本一の導入数を誇ります。フェアウェイ乗り入れ可能で移動も快適、【セグウェイでゴルフ】を是非体験してみて下さい。\n\n【お得プランの一部をご紹介】\n・全日廻り放題!*当日の天候、日没状況により、追加ラウンドできない場合もございます。\n・お誕生月特典あり!\n・平日は食べ放題のランチバイキング、4サム割引きあり。\nお得で楽しい一日をお気軽にお過ごし下さい。",
"address": "茨城県取手市稲1340",
"latitude": 35.9061664,
"longitude": 140.0397556,
"highway": "常磐自動車道谷和原",
"golfCourseDetailUrl": "https://booking.gora.golf.rakuten.co.jp/guide/disp/c_id/80004",
"reserveCalUrl": "https://search.gora.golf.rakuten.co.jp/cal/disp/c_id/80004",
"ratingUrl": "https://booking.gora.golf.rakuten.co.jp/voice/detail/c_id/80004",
"golfCourseImageUrl": "https://gora.golf.rakuten.co.jp/img/golf/80004/photo1.jpg",
"evaluation": 3.5
}
},
以下略

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

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

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

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

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

tomato879241

2021/05/27 18:18

以下の部分がおかしいのでは? let task = session.dataTask(with: req, completionHandler: { (data , respons , error) in //セッションを終了 session.finishTasksAndInvalidate() URLSessionの使い方の例は探せばそこら中にあるので、探してみてね。
urota

2021/05/28 15:20

ご返信ありがとうございます。 早速調べてみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問