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

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

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

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

Q&A

解決済

1回答

825閲覧

Swift 経路を表示したい

globalplus

総合スコア119

Swift

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

0グッド

0クリップ

投稿2019/12/24 18:59

編集2019/12/25 03:56

このページこのページを参考にしました
独自に座標を取得して逆ジオコーディングをしピンを置き、ピンをタップした吹き出しの中に経路ボタンを実装した所までは出来たのですが、経路ボタンを押すと

下記のコード内の
// 現在地と目的地を含む表示範囲を設定する
self.showUserAndDestinationOnMap()
} as! MKDirections.DirectionsHandler)
にThread 1: signal SIGABRTが出てしまいます

変数userLocationとdestLocationを強制アンラップしているからアプリが落ちてしまうのではないかと予測を立てていますが、はっきりとした原因はわかっていません。
アドバイス頂ければ嬉しいです。よろしくお願いします。

class FirstViewController: UIViewController, CLLocationManagerDelegate { @IBOutlet weak var mapView: MKMapView! let locationManager = CLLocationManager() let geocoder = CLGeocoder() let annotation = MKPointAnnotation() var userLocation: CLLocationCoordinate2D! var destLocation: CLLocationCoordinate2D! let regionRadius: CLLocationDistance = 1000 override func viewDidLoad() { super.viewDidLoad() locationManager.delegate = self as CLLocationManagerDelegate self.mapView.delegate = self } func geocoding() { //逆ジオコーディング let location = CLLocation(latitude: {doubleLatitude(独自に取得した緯度です)}(), longitude: {doubleLongitude(独自に取得した経度です)}()) CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in guard let placemark = placemarks?.first, error == nil else { return } self.destLocation = CLLocationCoordinate2DMake(placemark.location!.coordinate.latitude, placemark.location!.coordinate.longitude) print("逆ジオコーディングの中") //ピン self.annotation.coordinate = CLLocationCoordinate2DMake(doubleLatitude, doubleLongitude);self.mapView.addAnnotation(self.annotation) self.mapView.addAnnotation(self.annotation) print("ピンを置きました") //アノテーション let artwork = Artwork(title: "後で決める", locationName: "後で決める", discipline: "後で決める", coordinate: CLLocationCoordinate2D(latitude: doubleLatitude, longitude: doubleLongitude)) self.mapView.addAnnotation(artwork) } }) } //経路表示 @objc func buttonEvent(_ sender: UIButton) { // 現在地と目的地のMKPlacemarkを生成 let fromPlacemark = MKPlacemark(coordinate:userLocation, addressDictionary:nil) let toPlacemark = MKPlacemark(coordinate:destLocation, addressDictionary:nil) // MKPlacemark から MKMapItem を生成 let fromItem = MKMapItem(placemark:fromPlacemark) let toItem = MKMapItem(placemark:toPlacemark) // MKMapItem をセットして MKDirectionsRequest を生成 let request = MKDirections.Request() request.source = fromItem request.destination = toItem request.requestsAlternateRoutes = false // 単独の経路を検索 request.transportType = MKDirectionsTransportType.any let directions = MKDirections(request:request) directions.calculate(completionHandler: { (response:MKDirections.Response!, error:NSError!) -> Void in response.routes.count if (error != nil || response.routes.isEmpty) { return } let route: MKRoute = response.routes[0] as MKRoute // 経路を描画 self.mapView.addOverlay(route.polyline) // 現在地と目的地を含む表示範囲を設定する self.showUserAndDestinationOnMap() //Thread 1: signal SIGABRTのエラーです(エラー内容は下記に記載↓) } as! MKDirections.DirectionsHandler) } //地図上に現在地、目的地、経路がちょうど収まるように表示 func showUserAndDestinationOnMap() { // 現在地と目的地を含む矩形を計算 let maxLat:Double = fmax(userLocation.latitude, destLocation.latitude) let maxLon:Double = fmax(userLocation.longitude, destLocation.longitude) let minLat:Double = fmin(userLocation.latitude, destLocation.latitude) let minLon:Double = fmin(userLocation.longitude, destLocation.longitude) // 地図表示するときの緯度、経度の幅を計算 let mapMargin:Double = 1.5; // 経路が入る幅(1.0)+余白(0.5) let leastCoordSpan:Double = 0.005; // 拡大表示したときの最大値 let span_x:Double = fmax(leastCoordSpan, fabs(maxLat - minLat) * mapMargin); let span_y:Double = fmax(leastCoordSpan, fabs(maxLon - minLon) * mapMargin); let span:MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: span_x, longitudeDelta: span_y); // 現在地を目的地の中心を計算 let center:CLLocationCoordinate2D = CLLocationCoordinate2DMake((maxLat + minLat) / 2, (maxLon + minLon) / 2); let region:MKCoordinateRegion = MKCoordinateRegion(center: center, span: span); mapView.setRegion(mapView.regionThatFits(region), animated:true); } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { switch status { case .notDetermined: locationManager.requestWhenInUseAuthorization() case .authorizedWhenInUse: locationManager.startUpdatingLocation() default: break } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { //無理やり!でアンラップしました←ここが間違っている? userLocation = CLLocationCoordinate2DMake(manager.location!.coordinate.latitude, manager.location!.coordinate.longitude) if let coordinate = locations.last?.coordinate { // 現在地を拡大して表示する let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01) let region = MKCoordinateRegion(center: coordinate, span: span) mapView.region = region } guard let newLocation = locations.last else { return } self.latitude.text = "".appendingFormat("%.4f", newLocation.coordinate.latitude) self.longitude.text = "".appendingFormat("%.4f", newLocation.coordinate.longitude) let location = locations.first let latitude = location?.coordinate.latitude let longitude = location?.coordinate.longitude print("緯度: (latitude!)\n経度: (longitude!)") } // 位置情報取得に失敗した時に呼び出されるデリゲート. func locationManager(manager: CLLocationManager!,didFailWithError error: NSError!){ print("locationManager error") } func centerMapOnLocation(location: CLLocation) { let coordinateRegion = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: regionRadius, longitudinalMeters: regionRadius) mapView.setRegion(coordinateRegion, animated: true) } } extension FirstViewController: MKMapViewDelegate { // 1 func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { // 2 guard let annotation = annotation as? Artwork else { return nil } // 3 let identifier = "marker" var view: MKMarkerAnnotationView // 4 if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKMarkerAnnotationView { dequeuedView.annotation = annotation view = dequeuedView } else { // 5 view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier) view.canShowCallout = true view.calloutOffset = CGPoint(x: -5, y: 5) //右ボタンをアノテーションビューに追加する。 let button = UIButton() button.frame = CGRect(x: 0,y: 0,width: 70,height: 50) button.setTitle("経路", for: .normal) button.backgroundColor = UIColor.green button.setTitleColor(UIColor.white, for:.normal) button.addTarget(self, action: #selector(buttonEvent(_:)), for: UIControl.Event.touchUpInside) view.rightCalloutAccessoryView = button } return view } }

エラー内容

Could not cast value of type '(Swift.Optional<__C.MKDirectionsResponse>, Swift.Optional<__C.NSError>) -> ()' (0x1e172caf8) to '(Swift.Optional<__C.MKDirectionsResponse>, Swift.Optional<Swift.Error>) -> ()' (0x1e172cc30).

修正後コード

directions.calculate(completionHandler: { (response:MKDirections.Response?, error:Error?) -> Void in response!.routes.count if (error != nil || response!.routes.isEmpty) { return } let route: MKRoute = response!.routes[0] as MKRoute // 経路を描画 self.mapView.addOverlay(route.polyline) // 現在地と目的地を含む表示範囲を設定する self.showUserAndDestinationOnMap() })

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

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

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

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

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

guest

回答1

0

ベストアンサー

ソース全部読むのが面倒なので、エラーの原因だけ書きますが、

calculate(completionHandler:)completionHandlerに渡すクロージャの型は

https://developer.apple.com/documentation/mapkit/mkdirections/directionshandler

によると
typealias DirectionsHandler = (MKDirections.Response?, Error?) -> Void
と定義されています。

一方、あなたの実装は
(response:MKDirections.Response!, error:NSError!) -> Void
となっており、型が一致しません。

おそらくどこからのコピペでしょうが、それを無理矢理 as! MKDirections.DirectionsHandlerと強制的にキャストして対応した方法も間違っています。

正しい解決方法は型を揃えることです。
つまり

directions.calculate(completionHandler: {

(response:MKDirections.Response!, error:NSError!) -> Void in

directions.calculate(completionHandler: {

(response:MKDirections.Response?, error:Error?) -> Void in

もしくは

directions.calculate(completionHandler: { response, error in

などと省略形で書いても良いとは思います。
as! MKDirections.DirectionsHandlerは不要です。

投稿2019/12/25 00:41

編集2019/12/25 00:43
takabosoft

総合スコア8356

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

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

globalplus

2019/12/25 03:46 編集

ありがとうございます。説明通りに書き直しました。 エラーは消えたのですが、経路ボタンを押しても経路が描画されません。 もしよかったらまた教えて頂けませんか? 修正後コードを記載しました
takabosoft

2019/12/25 07:10

buttonEvent関数が呼ばれているかどうかブレークポイントを張るなりしてどこまで期待通りに動作しているか一つ一つ確認してください。
globalplus

2019/12/25 11:25

self.showUserAndDestinationOnMap()の下に print("経路を描画しました")を記述し、コンソールを確認した所、 経路を描画しましたと出力されました。 という事はself.showUserAndDestinationOnMap()が動いているという意味だと思うのですが実際に経路は描画されていません。 他に確認すべきところはありますか?
globalplus

2019/12/25 21:18

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { let renderer = MKPolylineRenderer(overlay: overlay) renderer.strokeColor = UIColor.blue renderer.lineWidth = 4.0 return renderer } を追加したら経路が表示されました。 takabosoftさんの回答がなければ辿りつかなかったのでベストアンサーをさせていただきます。 ありがとうございました。よかったらまたよろしくお願いします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問