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

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

ただいまの
回答率

89.07%

目的地への経路を地図上で表示させたい

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 137

sennin2911

score 4

リンクの動画を見ながら、同じように設定しましたが、検索しようとするとエラーが発生し、シミュレータが止まります。

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {

    @IBOutlet weak var textFieldForAddress: UITextField!
    @IBOutlet weak var getDirectionsButton: UIButton!
    @IBOutlet weak var map: MKMapView!

    var locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingHeading()

        map.delegate = self

    }

    @IBAction func getDirecitonsTapped(_ sender: Any) {
        getAddress()
    }

    //緯度経度検索メゾット
    func getAddress() {

        let geoCoder = CLGeocoder()
        geoCoder.geocodeAddressString(textFieldForAddress.text!) { (placemarks, error) in
            guard let placemarks = placemarks, let location = placemarks.first?.location
                else {
                    print("No Location Found")
                    return
            }
            print(location)
            self.mapThis(destinationCord: location.coordinate)
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print(locations)
    }
    func mapThis(destinationCord : CLLocationCoordinate2D) {
        let sourceCordinate = (locationManager.location?.coordinate)!

        let sourcePlaceMark = MKPlacemark(coordinate: sourceCordinate)
        let destPlaceMark = MKPlacemark(coordinate: destinationCord)

        let sourceItem = MKMapItem(placemark: sourcePlaceMark)
        let destItem = MKMapItem(placemark: destPlaceMark)

        let destinationRequest = MKDirections.Request()
        destinationRequest.source = sourceItem
        destinationRequest.destination = destItem
        destinationRequest.transportType = .automobile
        destinationRequest.requestsAlternateRoutes = true

        let directions = MKDirections(request: destinationRequest)
        directions.calculate { (response, error) in
            guard let response = response else {
                if let error = error{

                    print("Something is wrong")

                }
                return
            }

            let route = response.routes[0]
            self.map.addOverlay(route.polyline)
            self.map.setVisibleMapRect(route.polyline.boundingMapRect, animated: true)

        }


    }

    //Map上に線を引くメゾット
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        let render = MKPolygonRenderer(overlay: overlay as! MKPolyline)
        render.strokeColor = .blue
        return render
    }



}

エラー箇所のポイント

func mapThis(destinationCord : CLLocationCoordinate2D) {
        let sourceCordinate = (locationManager.location?.coordinate)!

エラーの内容
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

状態①
コンソールへの表示(緯度経度、時間等)は問題ありません。

状態②
県名(Kyoto)を入れるとエラーでシミュレータが止まります。

状態③
マップ自体は正常で、移動、拡大縮小ができます。

以上、助言をよろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

参考にされた動画は拝見していませんが、とりあえず動く方法についてコメントいたします。

シミュレータで動かすとなると、多少ソースコードを変更する必要がありそうです。
また、一部のメソッド名が紛らわしてく間違えていますので、それを修正する必要があります。

まずは、ユーザに位置情報を取得する許可を得るための設定が必要となります。

        locationManager.requestAlwaysAuthorization()
        locationManager.requestWhenInUseAuthorization()

この記述があるため、以下の2つについて plist を設定する必要があります(設定を行なっていなければ、実行時にデバッグエリアにメッセージが出ていますのでご確認ください)。

  • Privacy - Location Always Usage Description
  • Privacy - Location When In Use Usage Description

次に、位置情報の取得方法を変更します。

現在のコードだと向きが変わった時に通知が届くようになっていますが、シミュレータで実行すると「向きの変化」を伝えることができないようです。

一方、位置の変化であれば通知できますので、位置の変化を検知するように変更します。

        // MARK: 向き(heading)の変化ではなく、位置の変化を取得する
        //locationManager.startUpdatingHeading()
        locationManager.startUpdatingLocation()

次は、経路を表示する関数の処理を変更します。

エラーの内容
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

このエラーが出ている直接的な原因は、現在位置が取得できていないにもかかわらず位置情報を取得(オプショナル型を強制的にアンラップ)していることが原因となります。

したがって、位置情報が取得できていない時(プロパティがnilのとき)は処理を中止するようにします。

    func mapThis(destinationCord : CLLocationCoordinate2D) {
        // MARK: 位置情報が取得できていない時の処理
        // let sourceCordinate = (locationManager.location?.coordinate)!
        guard let location = locationManager.location else {
            // 位置情報が取得できていない
            return
        }
        let sourceCordinate = location.coordinate

最後は間違っているメソッド名の修正です。

MKPolyLineRenderer(ポリライン)とすべきところをMKPolygonRenderer(ポリゴン)としているため、ここでも実行時エラーが発生しますので修正します。

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        MARK: メソッドの間違い
        //let render = MKPolygonRenderer(overlay: overlay)
        let render = MKPolylineRenderer(overlay: overlay)

コードの変更は以上となります。

次にシミュレータでの実行方法です。

起動そのものは通常通り Run (cmd + R)で大丈夫なのですが、その後現在位置を設定する必要があります。

いくつか設定されている場所から Tokyo を選ぶか、任意の緯度経度を入力します。

シミュレータの Features -> Location -> Custom Location で任意の座標を入力するか、あるいは Xcode から Debug -> Simulate Location -> Tokyo, Japan を選択して(あるいは、デバッグエリア近くの Simulate Location と表示される三角のボタンを使って)現在位置を変更します。

現在位置を変更したあとであれば、TextField に目的地を入れることで経路情報を表示させることが可能となります。

ただし、Apple Map のジオコーディング(住所から座標情報を得ること)はあまり住所情報をもっていないようで、地元民なら誰でも知っているランドマーク(駅名でも)から座標を得ることができないみたいなので、その点にはご注意ください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/06/23 21:29

    ご回答ありがとうございます。
    ご指摘のようにコードを変更しましたところ、別のエラーが生じました。

    エラー:
    "-[MKRoutePolyline _isSimple]: unrecognized selector sent to instance 0x60000123d450"

    発生箇所:AppDelegate.swiftファイル

    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate { ←ココ

    状態①
    県名(Kyoto)を入れると上記のエラーでシミュレータが止まります。

    ネットでエラー情報を検索したところ、「StoryBoardに設定するCustom Classのクラスが違うことが原因」とありましたが、確認したところ「ViewController」なので問題ないと思います。

    お忙しい中恐縮ですが、ご回答お願いします

    キャンセル

  • 2020/06/24 05:57

    カスタムクラスだけでなく、@IBOutlet や@IBAction などの接続がおかしい場合も同様のエラーが出てきたいと思いますので、そちらもご確認いただけますでしょうか。

    キャンセル

  • 2020/06/24 12:40

    @IBOutlet weak var textFieldForAddress: UITextField!
    @IBOutlet weak var getDirectionsButton: UIButton!
    @IBOutlet weak var map: MKMapView!
    @IBAction func getDIrectionsTapped(_ sender: Any)
    のUI部品をcontrol+クリックで確認しましたが、繋がっていることは確認しました。

    キャンセル

  • 2020/06/24 14:31

    Connections Inspector で調べてみるのが一番確実かと思いますが、結構埒が明かないときもありますし、時間の浪費にもなりますので、思い切って新しいプロジェクトを作り、Interface Builder で StoryBoardだけ新規作成し、ソースコードはそのまま流用してみるのも良いかもしれません。少なくともソースには決定的なミスはありませんでしたので、そのまま流用されても問題ないかと思います。

    キャンセル

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

  • ただいまの回答率 89.07%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る