Yahoo! iOSマップSDKをSwiftで使ってみる

# 概要
ios版のYMapKit(YahooのMap SDK)を使うことになったのですが、ググってもSwift版のサンプルコードが一つも見つからなかったので、書いておきます。（いろいろハマってたので、ごちゃごちゃして汚いですが)

- 参考記事: [本家チュートリアル(Objective-C)](http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/iphonesdk/tutorial2.html)

# 実装上の注意

SDKに付属されている画像ファイルは、Images.xcassetsに追加しても表示されない。
マニュアル通りにプロジェクトのリソースに追加すること。
http://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/iphonesdk/tutorial1.html

# 実装方法

## 地図の表示

```Hoge-Bridging-Header.h
#import <YMapKit/YMapKit.h>
```

```YahooMapViewController.swift
import UIKit

class YahooMapViewController: UIViewController, YMKMapViewDelegate {
  var map: YMKMapView?
  
  override func viewDidLoad() {
    super.viewDidLoad()
    // YMKMapViewのインスタンスを作成
    map = YMKMapView(frame: CGRectMake(0, 0, 320, 320), appid: "アプリケーションID")

    // 地図のタイプを指定 標準の地図を指定
    map!.mapType = UInt(YMKMapTypeStandard)
    
    // YMKMapViewを追加
    self.view = map!
    
    // YMKMapViewDelegateを登録
    map!.delegate = self
    
    // 地図の位置と縮尺を設定
    var center = CLLocationCoordinate2D.init();
    center.latitude = 35.6657214;
    center.longitude = 139.7310058;
    map!.region = YMKCoordinateRegionMake(center, YMKCoordinateSpanMake(0.002, 0.002));    
    // Do any additional setup after loading the view.
  }  
}

```

## ルート案内

~~~YahooMapViewController.swift

import UIKit

class MyAnnotation: NSObject, YMKAnnotation {
  var coordinate: CLLocationCoordinate2D
  var annotationTitle: String!
  var annotationSubtitle: String!
  var annotationIndex: Int
  
  init(locationCoordinate: CLLocationCoordinate2D, title: String!, subtitle: String!, index: Int) {
    coordinate = locationCoordinate
    annotationTitle = title
    annotationSubtitle = subtitle
    annotationIndex = index
  }
  
  func title() -> String! {
    return annotationTitle
  }
  
  func subtitle() -> String! {
    return annotationSubtitle
  }
}

class YahooMapViewController: BaseMapViewController, YMKMapViewDelegate, YMKRouteOverlayDelegate, YMKNaviControllerDelegate {
  var mapView: YMKMapView!
  var naviController: YMKNaviController? //ルート案内インスタンス
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    // YMKMapViewを生成する
    mapView = YMKMapView(frame: self.view.bounds, appid: "アプリケーションID"))
    // 地図のタイプを指定 標準の地図を指定
    mapView.mapType = UInt(YMKMapTypeStandard)
    mapView.showsUserLocation = true
    mapView.delegate = self
    
    self.view.addSubview(mapView)
    
    let startLocation = CLLocation.init(latitude: 35.6657214, longitude: 139.7310058) // Midtoun
    let goalLocation = CLLocation.init(latitude: 35.710063, longitude: 139.8107)
    locate(startLocation)
    navigate(startLocation, goalLocation: goalLocation, startTitle: "現在地", goalTitle: "スカイツリー")
  }
  
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
  
  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    mapView.frame = self.view.bounds
    self.view.layoutIfNeeded()
  }

  // 指定された座標を表示する
  override func locate(location: CLLocation) {
    // 地図の位置と縮尺を設定
    let center = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
    mapView.region = YMKCoordinateRegionMake(center, YMKCoordinateSpanMake(0.002, 0.002));
    mapView.invalidateIntrinsicContentSize()
    
    // MyAnnotationの初期化
//    MyAnnotation* myAnnotation = [[MyAnnotation alloc] initWithLocationCoordinate:coordinate title:[[NSString alloc] initWithString:@"ミッドタウン"] subtitle:[[NSString alloc] initWithString:@"ミッドタウンです。"]];l
    //let myAnnotation = MyAnnotation.init(coord: center, title: "ミッドタウン", subTitle: "ミッドタウンです")

    // AnnotationをYMKMapViewに追加
    // mapView.addAnnotation(myAnnotation)
    
    // 地図上のマーカー表示用のアノテーション配列を作成
    var annotations: [AnyObject] = []
    annotations.append(MyAnnotation(locationCoordinate: center, title: "bbb", subtitle: "aaa", index: 0))
    setAnnotations(annotations)
    
    //showPolyline()
  }
  
  func setAnnotations(annotations: [AnyObject]!) {
    mapView.removeAnnotations(mapView.annotations)
    
    if annotations != nil && annotations.count > 0 {
      mapView.addAnnotations(annotations)
    }
  }
  
  func mapView(mapView: YMKMapView!, viewForAnnotation annotation: YMKAnnotation!) -> YMKAnnotationView! {
    if annotation is MyAnnotation {
      // マーカーのビューを引数のannotationを用いて作成する
      let pin = YMKPinAnnotationView(annotation: annotation, reuseIdentifier: "Pin")
      //アイコンイメージの変更
      pin.image = UIImage.init(named: "goal");
      pin.animatesDrop = true
      // アイコンのイメージのどこを基準点にするか設定
      let centerOffset = CGPointMake(15, 15);
      pin.centerOffset = centerOffset
      return pin
    }
    return nil
  }
  
  // ルート案内をする
  override func navigate(startLocation: CLLocation, goalLocation: CLLocation, startTitle: String, goalTitle: String) {
    let startPos = CLLocationCoordinate2DMake(startLocation.coordinate.latitude, startLocation.coordinate.longitude);
    let goalPos  = CLLocationCoordinate2DMake(goalLocation.coordinate.latitude, goalLocation.coordinate.longitude);
    
    // YMKRouteOverlayを作成
    let routeOverlay = YMKRouteOverlay.init(appid: "アプリケーションID")
    //YMKRouteOverlayDelegateを設定
    routeOverlay.delegate = self
    // 出発地ピンの吹き出し設定
    routeOverlay.setStartTitle(startTitle)
    // 目的地ピンの吹き出し設定
    routeOverlay.setGoalTitle(goalTitle)
    // 出発地、目的地、移動手段を設定
    routeOverlay.setRouteStartPos(startPos, withGoalPos: goalPos, withTraffic: TRAFFIC_WALK)
    // ルートの検索
    routeOverlay.search()
  }
  
  func showPolyline() {
    // YMKPolylineを作成
    var coords: [CLLocationCoordinate2D] = []
    coords.append(CLLocationCoordinate2D.init(latitude: 35.6657214, longitude: 139.7310058))
    coords.append(CLLocationCoordinate2D.init(latitude: 35.670168, longitude: 139.702687))
    coords.append(CLLocationCoordinate2D.init(latitude: 35.683061, longitude: 139.702687))
    coords.append(CLLocationCoordinate2D.init(latitude: 35.690921, longitude: 139.700258))

    let line = YMKPolyline.init(coordinates: &coords, count: 4)
    // YMKPolylineをYMKMapViewに追加
    mapView.addOverlay(line)
  }

  // ルート検索が正常に終了した場合
  func finishRouteSearch(routeOverlay: YMKRouteOverlay) {
    // YMKRouteOverlayをYMKMapViewに追加
    mapView.addOverlay(routeOverlay)
    
//    // YMKNaviControllerを作成しYMKRouteOverlayインスタンスを設定
//    naviController = YMKNaviController.init(routeOverlay: routeOverlay)
//    
//    // YMKMapViewインスタンスを設定
//    naviController!.setMapView(mapView)
//    
//    // YMKNaviControllerDelegateを設定
//    naviController!.delegate = self
//    
//    // 案内処理を開始
//    naviController!.start()
  }

  // ルート検索が正常に終了しなかった場合
  func errorRouteSearch(routeOverlay: YMKRouteOverlay!, withError error: Int32) {
    let alert = UIAlertView.init(title: "エラー", message: "ルート検索エラー", delegate: self, cancelButtonTitle: "OK")
    alert.show()
  }

  // overlay追加イベント
  func mapView(mapView: YMKMapView!, viewForOverlay overlay: YMKOverlay!) -> YMKOverlayView! {
    print("mapView:viewForOverlay")
    // 追加されたoverlayがYMKPolylineか確認
    if overlay.isKindOfClass(YMKPolyline) {
      let line: YMKPolyline = overlay as! YMKPolyline
      //YMKPolylineViewを作成
      let wkYMKPolylineView = YMKPolylineView.init(overlay: overlay)
      //ラインの色を青に設定
      wkYMKPolylineView.strokeColor = UIColor.init(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
      wkYMKPolylineView.fillColor =   UIColor.init(red: 0.0, green: 0.0, blue: 1.0, alpha: 1.0)
      //ラインの太さ
      wkYMKPolylineView.lineWidth = 5
      return wkYMKPolylineView;
    }
    
    // 追加されたoverlayがYMKRouteOverlayか確認
    if overlay.isKindOfClass(YMKRouteOverlay) {
      // YMKRouteOverlayViewを作成
      let wkYMKOverlayView: YMKRouteOverlayView = YMKRouteOverlayView.init(routeOverlay: overlay as! YMKRouteOverlay)
      // 出発地ピンを非表示
      wkYMKOverlayView.startPinVisible = true
      // 目的地ピンを非表示
      wkYMKOverlayView.goalPinVisible = true
      // 経由点ピンを非表示
      wkYMKOverlayView.routePinVisible = true
      return wkYMKOverlayView;
    }
    return nil;
  }

  // 現在位置更新された場合
  func naviController(naviController: YMKNaviController!, didUpdateUserLocation userLocation: YMKUserLocation!) {
     print("naviController:didUpdateUserLocation")
  }

  // 現在位置取得エラーが発生した場合
  func naviController(naviController: YMKNaviController!, didFailToLocateUserWithError error: NSError!) {
    print("naviController:didFailToLocateUserWithError")
  }

  // 現在位置の精度が悪い場合
  func naviControllerAccuracyBad(naviController: YMKNaviController!, didUpdateUserLocation userLocation: YMKUserLocation!) {
    print("naviControllerAccuracyBad")
  }

  // ルートから外れたと判断された場合
  func naviControllerRouteOut(naviController: YMKNaviController!, didUpdateUserLocation userLocation: YMKUserLocation!) {
    print("naviControllerRouteOut")
  }

  // 目的地に到着した場合
  func naviControllerOnGoal(naviController: YMKNaviController!, didUpdateUserLocation userLocation: YMKUserLocation!) {
    print("naviControllerOnGoal")
    // 案内処理を継続しない場合は停止させる
    naviController.stop()
  }
}
```