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

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

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

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

API

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

Q&A

解決済

1回答

1852閲覧

【Swift】APIから取得した値から、Mapkitを用いてピンを立てる

reo0612

総合スコア2

Swift

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

API

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

0グッド

0クリップ

投稿2020/09/24 11:49

編集2020/09/24 11:58

前提・実現したいこと

ホットペッパーのグルメサーチAPIを使用して現在地から飲食店を検索し、Mapkitを使用して
その場所にピンを立てるアプリを作ろうと思っています。

APIから取ってくる値が1つであれば、MapViewにピンを立ててくれるのですが、APIから取ってくる値が2つとなってくるとfunc annotationPin()中のfor文がちゃんと回ってくれないです。

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

Thread 1: Fatal error: Index out of range

該当のソースコード

swift

1// ViewController.swift 2 3import UIKit 4import CoreLocation 5import MapKit 6import WebKit 7import Toast_Swift 8 9class ViewController: UIViewController { 10 let deligate:AppDelegate = UIApplication.shared.delegate as! AppDelegate 11 let dataRequest = Datarequest() 12 13 var webView = WKWebView() 14 15 @IBOutlet weak var MapView: MKMapView! 16 var locationManager: CLLocationManager! = CLLocationManager() 17// ボタン 18 @IBOutlet weak var UserLocationButton: UIButton! 19 @IBOutlet weak var searchButton: UIButton! 20// TextField 21 @IBOutlet weak var SearchTextField: UITextField! 22 23 override func viewDidLoad() { 24 super.viewDidLoad() 25//  マップ機能 26 locationManager.delegate = self 27 MapView.delegate = self 28// アプリ使用中に一情報サービスを使用するユーザーの許可を要求する 29 locationManager.requestWhenInUseAuthorization() 30// 精度 31 locationManager.desiredAccuracy = kCLLocationAccuracyBest 32// 更新頻度(メートル) 33 locationManager.distanceFilter = 100 34 locationManager.startUpdatingLocation() 35// 現在地に照準を合わせる 36// 距離の倍率 37 let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) 38// MapView.userLocation.coordinateで現在地が取得可能 39 let resion = MKCoordinateRegion(center: MapView.userLocation.coordinate, span: span) 40// 照準を合わせる 41 MapView.region = resion 42// ユーザーの位置を追跡する 43 MapView.userTrackingMode = MKUserTrackingMode.follow 44// コンパス 45 let compas = MKCompassButton(mapView: MapView) 46 compas.compassVisibility = .hidden 47 navigationItem.rightBarButtonItem = UIBarButtonItem(customView: compas) 48 MapView.showsCompass = false 49// ボタン関連 50 UserLocationButton.layer.cornerRadius = 20.0 51 UserLocationButton.layer.shadowOpacity = 0.8 52 UserLocationButton.layer.shadowRadius = 20.0 53 UserLocationButton.layer.shadowColor = UIColor.black.cgColor 54 UserLocationButton.layer.shadowOffset = CGSize(width: 1, height: 1) 55 UserLocationButton.layer.shadowPath = CGPath(ellipseIn: CGRect(x: 0, y: 0, width: 18, height: 18), transform: nil) 56 searchButton.layer.cornerRadius = 15 57// 保存されているURLを削除 58 UserDefaults.standard.removeObject(forKey: "url") 59 } 60 61//  検索ボタン 62 @IBAction func SearchButton(_ sender: Any) { 63 guard SearchTextField.text!.count > 0 else { 64 SearchTextField.resignFirstResponder() 65 self.view.makeToast("文字を入力して下さい。", duration: 2.0, position: .center) 66 return 67 } 68 deligate.userSearchKeyword = SearchTextField.text! 69 SearchTextField.text = "" 70 SearchTextField.resignFirstResponder() 71 72 dataRequest.request { (name, lat, lng) in 73// 検索結果が0だったら 74 if (name.isEmpty == true && lat.isEmpty == true && lng.isEmpty == true){ 75 self.view.makeToast("検索出来ませんでした。", duration: 2.0, position: .center) 76 return 77 } 78// 検索結果があれば、pinを立てる 79 self.annotationPin() 80 } 81 } 82// MapViewにピンを立てる 83 func annotationPin(){ 84 for (index,pintitle) in self.deligate.resultName.enumerated(){ 85// ピン 86 let pin = MKPointAnnotation() 87// タイトル 88 pin.title = pintitle 89 print("(index)番目の(deligate.resultName[index])をピンの名前にしました。") 90// 場所 91 let pinlocations: [CLLocationCoordinate2D] = [CLLocationCoordinate2DMake(self.deligate.resultLat[index], self.deligate.resultLng[index])] 92//    ===========ここにThread 1: Fatal error: Index out of rangeというエラーメッセージが表示されます。=========== 93 pin.coordinate = pinlocations[index] 94 print("(index)番目の(pinlocations[index])の位置にピンを指定しました。") 95// mapViewにpinをセット 96 self.MapView.addAnnotation(pin) 97 } 98 } 99 100 // 現在地情報を取得したときに呼ばれるメソッド 101 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 102// 現在地が取得出来たら 103 guard let gps = (manager.location?.coordinate) else { 104 self.view.makeToast("現在地が取得できませんでした。", duration: 2.0, position: .center) 105 return 106 } 107 print("現在地を取得しました。") 108 // 現在地の緯度・経度を取得 109 deligate.userLat = Float(gps.latitude) 110 deligate.userLng = Float(gps.longitude) 111 } 112 113// ボタンをタップすると現在地に飛ぶボタン 114 @IBAction func userLoacationTap(_ sender: Any) { 115 revarseGeocoding() 116 } 117 118 func revarseGeocoding(){ 119 let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) 120 let region = MKCoordinateRegion(center: MapView.userLocation.coordinate, span: span) 121// 照準を合わせる 122 MapView.region = region 123// ユーザーの位置を追跡するためのアプリ 124 MapView.userTrackingMode = MKUserTrackingMode.follow 125 } 126 127 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 128 SearchTextField.resignFirstResponder() 129 } 130} 131 132// 許可を求めるためのdegateメソッド 133extension ViewController: CLLocationManagerDelegate{ 134 func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 135 136 switch status { 137// 許可されていない場合 138 case .notDetermined: 139// 許可を求める 140 manager.requestWhenInUseAuthorization() 141 case .restricted, .denied: 142// 何もしない 143 break 144 case .authorizedAlways, .authorizedWhenInUse: 145// 現在地の取得を開始 146 manager.stopUpdatingLocation() 147 default: 148 break 149 } 150 } 151} 152 153// ピンを追加した時に呼ばれる(ピンを加工したりする) 154extension ViewController: MKMapViewDelegate{ 155 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { 156 // 自分の現在地は置き換えない 157 if (annotation is MKUserLocation) { 158 return nil 159 } 160 let identifier = "pin" 161 var annotationView: MKMarkerAnnotationView! 162 163 if annotationView == nil { 164// MKAnnotationViewを設定 165 annotationView = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier) 166 } 167 168 annotationView.glyphText = "????" 169 annotationView.markerTintColor = UIColor.orange 170 annotationView.annotation = annotation 171 return annotationView 172 } 173// ピンが選択された時に呼ばれる 174 func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) { 175 print("pinが選択されました。") 176 177 for url in deligate.resultUrl { 178 let webVC = resultWebViewController() 179 UserDefaults.standard.set(url, forKey: "url") 180 print("(UserDefaults.standard.object(forKey: "url")!)が保存されています。") 181 self.present(webVC, animated: true, completion: nil) 182// 0.5秒後にpinの選択解除 183 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2) { 184 view.isSelected = false 185 } 186 187    } 188} 189 190

swift

1// AppDelegate.swift 2 3import UIKit 4 5@UIApplicationMain 6class AppDelegate: UIResponder, UIApplicationDelegate { 7// APIで検索に必要な値 8 var userLat:Float = 0.0 9 var userLng:Float = 0.0 10 var userSearchKeyword = "" 11// APIから取得した値を格納する配列 12 var resultName:[String] = [] 13 var resultLat:[Double] = [] 14 var resultLng:[Double] = [] 15 var resultUrl:[String] = [] 16//省略

swift

1// DataRequest.swift 2 3import Foundation 4import SwiftyJSON 5import Alamofire 6import Toast_Swift 7import CoreLocation 8 9class Datarequest { 10 11 let deligate = UIApplication.shared.delegate as! AppDelegate 12 13 func request(_ after:@escaping([String],[Double],[Double]) -> ()) { 14 let apiKey = "APIキー" 15// 検索する度に、配列をリセットする 16 17 self.deligate.resultName.removeAll() 18 self.deligate.resultLat.removeAll() 19 self.deligate.resultLng.removeAll() 20 self.deligate.resultUrl.removeAll() 21 22 let prams : Parameters = [ 23 "key":apiKey, 24 "keyword":deligate.userSearchKeyword, 25 "lat":deligate.userLat, 26 "lng":deligate.userLng, 27 "range":5, 28 "count":2, 29 "format":"json", 30 ] 31 32 AF.request("http://webservice.recruit.co.jp/hotpepper/gourmet/v1/", parameters: prams).responseJSON { (responce) in 33 34 switch responce.result{ 35 36 case .success: 37 38 for i in 0...1{ 39 let json:JSON = JSON(responce.data as Any) 40 let name = json["results"]["shop"][i]["name"].string 41 let lat = json["results"]["shop"][i]["lat"].double 42 let lng = json["results"]["shop"][i]["lng"].double 43 let url = json["results"]["shop"][i]["urls"]["pc"].string 44 45 if (name != nil && lat != nil && lng != nil && url != nil){ 46 self.deligate.resultName.append(name!) 47 self.deligate.resultLat.append(lat!) 48 self.deligate.resultLng.append(lng!) 49 self.deligate.resultUrl.append(url!) 50 } 51 } 52 53 case .failure(let error): 54 debugPrint(error) 55 return 56 } 57 after(self.deligate.resultName,self.deligate.resultLat,self.deligate.resultLng) 58 } 59 } 60}

試したこと

printで、配列に2つ、飲食店の名前と経度&緯度が格納されていることは確認済みです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

実際にコンパイルしていませんが、

Swift

1 func annotationPin(){ 2 // 略 3 let pinlocations: [CLLocationCoordinate2D] = [CLLocationCoordinate2DMake(self.deligate.resultLat[index], self.deligate.resultLng[index])] 4//    ===========ここにThread 1: Fatal error: Index out of rangeというエラーメッセージが表示されます。=========== 5 pin.coordinate = pinlocations[index]

この部分が間違っていませんでしょうか。

Swift

1 let pinlocations: [CLLocationCoordinate2D] = [CLLocationCoordinate2DMake(self.deligate.resultLat[index], self.deligate.resultLng[index])]

pinlocations は配列として定義しておきながら、実際に代入されている要素数は一つ(CLLocationCoordinate2DMake(self.deligate.resultLat[index], self.deligate.resultLng[index])のみ)です。

2つ目の要素は代入されていませんから、当然indexの値が1になると

Swift

1 pin.coordinate = pinlocations[index]

の部分でアクセス違反が起きて実行時エラーで落ちてしまいます。

ここは単純に

Swift

1 let pinlocations = CLLocationCoordinate2DMake(self.deligate.resultLat[index], self.deligate.resultLng[index]) 2 pin.coordinate = pinlocations

で良いと思いますが、いかがでしょうか。

投稿2020/09/24 13:40

TsukubaDepot

総合スコア5086

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

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

reo0612

2020/09/24 15:02

無事、MapViewに複数ピンを立てる事が出来ました! なるほど、実際に代入している要素数が配列の中に一つしかなかった為に2つ目の値が反映されなかったんですね。 丁寧に優しく教えて頂きありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問