23986


私は現在、MapKitを使っての地図アプリを作っているのですが、入力されている住所を引数に、緯度経度を出す関数を呼び出したはずなのですが上手く配列に入っておらず、fatal
error: Index out of range`で落ちてしまいます。  
_nameと_jyuusyoの配列には遷移前に、入力された住所と場所名が保存されています。  
Xcode Version 7.3です。

[code]

    import UIKit
    import MapKit
    import CoreLocation
    import QuartzCore
    
    
    let gamensize = UIScreen.mainScreen().bounds.size
    var ken = "千葉県"
    var _ido = [CLLocationDegrees]()
    var _keido = [CLLocationDegrees?]()
    var _name = ["東京ディズニーランド","東京タワー"]
    var _jyuusyo = ["千葉県浦安市舞浜１−１","東京都港区芝公園４丁目２−８"]
    
    class ViewController: UIViewController, MKMapViewDelegate{
    
        //MapViewの生成
        let myMapView = MKMapView()
    
        //配列
        var _jikan = [String]()
        var _syoyoujikan = [Int]()
    
        //時間表
        var a: Bool = true
        var i = 0
    
        //ステータスバー隠す
        override func prefersStatusBarHidden() -> Bool {
            return true
    
        }
    
        //渡された県に画面を合わせる
        func ken_settei(ken: String) {
            // geocoderを作成.
            let myGeocoder = CLGeocoder()
            let myAddress = ken
            // 正ジオコーディング開始
            myGeocoder.geocodeAddressString(myAddress, completionHandler: { (placemarks, error) -> Void in
                if let placemark = placemarks?[0] as? CLPlacemark! {
                    // 地名を入力して検索リストに有れば緯度経度を取得
                    if placemark != nil {
                        // 中心点の緯度経度.
                        let Lat: CLLocationDegrees = placemark!.location!.coordinate.latitude
                        let Lon: CLLocationDegrees = placemark!.location!.coordinate.longitude
                        let myCoordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(Lat, Lon)
    
                        print(placemark!.location!.coordinate.latitude)
                        print(placemark!.location!.coordinate.longitude)
    
                        // 縮尺.
                        let myLatDist : CLLocationDistance = 200000
                        let myLonDist : CLLocationDistance = 200000
    
                        // Regionを作成.
                        let Region: MKCoordinateRegion = MKCoordinateRegionMakeWithDistance(myCoordinate, myLatDist, myLonDist)
    
                        //regionに設定したマップの表示設定をMapViewに反映
                        self.myMapView.setRegion(Region, animated: true)
    
                    }else{
                        print("見つかりません")
                    }
                }
            })
    
    
        }
    
        //出発地点の緯度と経度、到達地点の緯度と経度で、ルートを表示(所要時間、距離も表示)
        func rutokensaku(ido: CLLocationDegrees, keido: CLLocationDegrees, t_ido: CLLocationDegrees, t_keido: CLLocationDegrees){
            // 出発点の緯度、経度を設定.
            let myLatitude: CLLocationDegrees = ido
            let myLongitude: CLLocationDegrees = keido
            // 目的地の緯度、経度を設定
            let requestLatitude: CLLocationDegrees = t_ido
            let requestLongitude: CLLocationDegrees = t_keido
    
            let fromCoordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(myLatitude, myLongitude)
            let requestCoordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(requestLatitude, requestLongitude)
    
            // PlaceMarkを生成して出発点、目的地の座標をセット.
            let fromPlace: MKPlacemark = MKPlacemark(coordinate: fromCoordinate, addressDictionary: nil)
            let toPlace: MKPlacemark = MKPlacemark(coordinate: requestCoordinate, addressDictionary: nil)
            // Itemを生成してPlaceMarkをセット.
            let fromItem: MKMapItem! = MKMapItem(placemark: fromPlace)
            let toItem: MKMapItem! = MKMapItem(placemark: toPlace)
    
            let myRequest:MKDirectionsRequest = MKDirectionsRequest()
    
            myRequest.source = fromItem
            myRequest.destination = toItem
    
            // 複数経路の検索
            myRequest.requestsAlternateRoutes = true
            // 移動手段を車に設定.
            myRequest.transportType = MKDirectionsTransportType.Automobile
            // MKDirectionsを生成してRequestをセット.
            let myDirections: MKDirections = MKDirections(request: myRequest)
            // 経路探索.
            myDirections.calculateDirectionsWithCompletionHandler { (response, error) -> Void in
    
                // NSErrorを受け取ったか、ルートがない場合.
                if error != nil || response!.routes.isEmpty {
                    print("エラーもしくはルートが無い")
                    self._syoyoujikan.append(999999)
                    return
                }
    
                let route: MKRoute = response!.routes[0] as MKRoute
                self._syoyoujikan.append(Int(route.expectedTravelTime/60))
    
                // mapViewにルートを描画.
                self.myMapView.addOverlay(route.polyline)
            }
        }
    
        //住所から緯度経度を取得するジオコーディング(配列に住所、緯度経度を追加)
        func Geocodering(jyuusyo: String) {
            // geocoderを作成.
            let myGeocoder = CLGeocoder()
            let myAddress = jyuusyo
    
            // 正ジオコーディング開始
            myGeocoder.geocodeAddressString(myAddress, completionHandler: { (placemarks, error) -> Void in
                if let placemark = placemarks?[0] as? CLPlacemark! {
                    // 地名を入力して検索リストに有れば緯度経度を取得
                    if placemark != nil {
    
                        _ido.append(placemark!.location!.coordinate.latitude)
                        _keido.append(placemark!.location!.coordinate.longitude)
    
                        let pin = MKPointAnnotation()
                        //ピンを刺す座標
                        let poji:CLLocationCoordinate2D = CLLocationCoordinate2DMake(placemark!.location!.coordinate.latitude, placemark!.location!.coordinate.longitude)
                        //ピンに座標指定
                        pin.coordinate = poji
                        pin.title = "\(_name[self.i])"
                        pin.subtitle = "\(_jyuusyo[self.i])"
    
                        self.i += 1
    
                        self.myMapView.addAnnotation(pin)
                        //アノテーション（ピン）のtitle, subtitleにそれぞれ緯度経度をセット.
    
                    }else{
                        print("見つかりません")
                    }
                }
            })
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            //入力された県に画面を合わせる
            ken_settei(ken)
    
            for var i = 0; i <  _jyuusyo.count ; i++ {
                self.Geocodering(_jyuusyo[i])
            }
    
            for var i = 0; i < _jyuusyo.count ; i++ {
                if i + 1 < _jyuusyo.count {
                    //経路を順番に表示
                    self.rutokensaku(_ido[i], keido: _keido[i]!, t_ido: _ido[i+1], t_keido: _keido[i+1]!)
                }else{
                    //帰り道の表示
                    self.rutokensaku(_ido[i], keido: _keido[i]!, t_ido: _ido[0], t_keido: _keido[0]!)
                }
            }
    
            myMapView.delegate = self
    
            //MapView生成の処理
            //サイズと位置
            myMapView.frame = self.view.frame
            self.view.addSubview(myMapView)
    
            //地図の形式
            myMapView.mapType = MKMapType.Standard
    
        }
    
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
        // ルートの表示設定.
        func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
    
            let route: MKPolyline = overlay as! MKPolyline
            let routeRenderer: MKPolylineRenderer = MKPolylineRenderer(polyline: route)
    
            // 線の太さ
            routeRenderer.lineWidth = 4.0
            // 線の色
            routeRenderer.strokeColor = UIColor.redColor()
            return routeRenderer
        }
    }
    
[/code]


CC BY-SA 3.0
2016-04-12T08:20:11.390
23945
2016-04-13T08:19:35.320
2016-04-13T08:19:35.320
5519
15133
question
swift
関数で呼び出した所、上手く配列に入りません


クラッシュしているのはおそらく、２回目のfor文の中で`_ido[i]`や`_keido[i]`を参照しているところかと思います。

最初のfor文で`Geocodering()`メソッドを実行していて、そこで`_ido`や`_keido`に値を追加しているので、値があるはず、と思われているかもしれませんが、`CLGeocoder.geocodeAddressString()`メソッドは非同期で実行されるので、次のfor文に入ったときにはまだ結果は帰ってきていません。  
（geocodeAddressString()のコールバックにブレークポイントを置くかprint文を書いて実行してみると、実行されてないことがよく分かります）

[code]

    for var i = 0; i <  _jyuusyo.count; i++ {
        self.Geocodering(_jyuusyo[i])
    }
    
    
    for var i = 0; i < _jyuusyo.count; i++ {
        if i + 1 < _jyuusyo.count {
            //経路を順番に表示
            self.rutokensaku(_ido[i], keido: _keido[i]!, t_ido: _ido[i+1], t_keido: _keido[i+1]!)
        } else {
            //帰り道の表示
            self.rutokensaku(_ido[i], keido: _keido[i]!, t_ido: _ido[0], t_keido: _keido[0]!)
        }
    }
    
[/code]

とりあえず簡単に直すのであれば、２回目のfor文を`geocodeAddressString()`の`completionHandler`の中に書くといいと思います。

[code]

    myGeocoder.geocodeAddressString(myAddress, completionHandler: { (placemarks, error) -> Void in
        if let placemark = placemarks?[0] as? CLPlacemark! {
            // 地名を入力して検索リストに有れば緯度経度を取得
            if placemark != nil {
    
                ...
    
                self.myMapView.addAnnotation(pin)
                //アノテーション（ピン）のtitle, subtitleにそれぞれ緯度経度をセット.
    
                // ２回目のfor文をこの辺りに移動する
                for var i = 0; i < _jyuusyo.count ; i++ {
                    if i + 1 < _jyuusyo.count {
                        //経路を順番に表示
                        self.rutokensaku(_ido[i], keido: _keido[i]!, t_ido: _ido[i+1], t_keido: _keido[i+1]!)
                    }else{
                        //帰り道の表示
                        self.rutokensaku(_ido[i], keido: _keido[i]!, t_ido: _ido[0], t_keido: _keido[0]!)
                    }
                }
    
            }else{
                print("見つかりません")
            }
        }
    })
    
[/code]


CC BY-SA 3.0
2016-04-13T08:18:58.960
23986
2016-04-13T08:18:58.960
5519
23945
answer