[はじめてのiOSアプリ]xcodeで地図アプリを作成（その７）

# はじめに

iOSアプリを作ってみたいけど
何から始めて良いのかわからない

とりあえず、
「やってみました」記事を参考に
地図アプリを真似てみようと思う

という記事の７回目です。

今回は、地図を拡大・縮小までします。

# 拡大・縮小表示
1. 比率を定数として定義
   - 今回、拡大縮小比に[[黄金比](https://ja.wikipedia.org/wiki/黄金比)]を使います
   - ViewController.swift を以下のように修正
     - 【なぜ？】
         - １より大きな値であれば、好きな値を選んでOK
         - 拡大でも縮小でも使うので、定数(let)とする
         - さすが**黄金比**「いい感じ」で拡大縮小される（と思う）

         ```swift:ViewController.swift
         class ViewController: UIViewController, CLLocationManagerDelegate {
             let goldenRatio = 1.618  // この行を追加
         
             @IBOutlet var mapView: MKMapView!
         ```
1. 排他(lock)変数を追加
   - ViewController.swiftの該当部分を以下のように修正
     - 【なぜ？】
         - 位置情報の更新や拡大・縮小のため、変数 mapView の値変更を同時に行わないよう排他(lock/unlock)する時に使用するため
         - 変数 mapView の値を同時に変更すると、アプリ異常終了の原因となるため

         ```swift:ViewController.swift
         class ViewController: UIViewController, CLLocationManagerDelegate {
             var myLock = NSLock()  // この行を追加
             let goldenRatio = 1.618
         ```


1. 拡大処理
   - ViewController.swiftの該当部分を以下のように修正
   - 拡大(ZoomIn)処理なので、**現在表示している領域より狭い範囲**を指定
     - 【なぜ？】
         - 拡大(ZoomIn)処理の内容を記述する
         - 変数 mapView の値を変更するので排他開始(lock)
         - mapView.region.span.latitudeDelta の値が表示範囲であるため
         - 上記変数の値を小さくしすぎない（今回は、0.005 より大きく制限）
         - 上記変数の値を直接変更せずに新規変数を作成（後述）
         - regionSpan.latitudeDelta に拡大した時の値を設定
         - regionSpan.longitudeDelta は設定しなくて問題ない
         - mapView.region.span に regionSpan を設定する（新規変数に置き換える）ことで、地図が拡大される
         - 変数 mapView の値変更が終了したので排他解除(unlock)


        ```swift:ViewController.swift
        @IBAction func clickZoomin(_ sender: Any) {
            print("[DBG]clickZoomin")
            myLock.lock()
            if (0.005 < mapView.region.span.latitudeDelta / goldenRatio) {
                print("[DBG]latitudeDelta-1 : " + mapView.region.span.latitudeDelta.description)
                var regionSpan:MKCoordinateSpan = MKCoordinateSpan()
                regionSpan.latitudeDelta = mapView.region.span.latitudeDelta / goldenRatio
                mapView.region.span = regionSpan
                print("[DBG]latitudeDelta-2 : " + mapView.region.span.latitudeDelta.description)
            }
            myLock.unlock()
        }
        ```
1. 縮小処理
   - ViewController.swiftの該当部分を以下のように修正
     - 【なぜ？】
         - 縮小(ZoomOut)処理の内容を記述する
         - 縮小(ZoomOut)処理なので、**現在表示している領域より広い範囲**を指定
         - あとは、拡大(ZoomIn)と同様なので説明は省略

        ```swift:ViewController.swift
        @IBAction func clickZoomout(_ sender: Any) {
            print("[DBG]clickZoomout")
            myLock.lock()
            if (mapView.region.span.latitudeDelta * goldenRatio < 150.0) {
                print("[DBG]latitudeDelta-1 : " + mapView.region.span.latitudeDelta.description)
                var regionSpan:MKCoordinateSpan = MKCoordinateSpan()
                regionSpan.latitudeDelta = mapView.region.span.latitudeDelta * goldenRatio
//            regionSpan.latitudeDelta = mapView.region.span.longitudeDelta * GoldenRatio
                mapView.region.span = regionSpan
                print("[DBG]latitudeDelta-2 : " + mapView.region.span.latitudeDelta.description)
            }
            myLock.unlock()
        }
        ```
1. 位置情報更新時の排他処理追加
   - ViewController.swiftの該当部分を以下のように修正
     - 【なぜ？】
         - GPSの位置情報更新（変数 mapViewの値変更）は、排他が必要な処理だから

        ```swift:ViewController.swift
        func locationManager(_ manager: CLLocationManager, didUpdateLocations locations:[CLLocation]) {
            let longitude = (locations.last?.coordinate.longitude.description)!
            let latitude = (locations.last?.coordinate.latitude.description)!

            myLock.lock()  // この行を追加
            mapView.setCenter((locations.last?.coordinate)!, animated: true)
            myLock.unlock()  // この行を追加
        }
        ```
1. テスト実行
   - Simulatorを起動し、「＋」ボタンや「ー」ボタンを押してみる
   - ボタンを押すたびに、地図が拡大・縮小された


# 今回の到達点
- 拡大・縮小ボタンを押すことで、地図も拡大・縮小するようになった

# おまけ
- 実は、今回の記事（ソースコード）は試行錯誤の結果です
- せっかくなので「おまけ」として不採用となった修正を記録に残します

## 拡大縮小率
- 最初は、2.0　を使っていました
- 縦と横(緯度と経度)がそれぞれ 2.0倍(もしくは1/2倍)される
- その結果、表示される範囲は４倍(もしくは1/4)倍される
- チョット違和感のある拡大・縮小となったので不採用となった

## 緯度・経度の変数値を直接変更（その１）
- 以下のように mapView.region.span のlatitudeDeltaとlongitudeDeltaを直接変更

```swift:ViewController.swift
mapView.region.span.latitudeDelta /= goldenRatio
mapView.region.span.longitudeDelta /= goldenRatio
// 途中省略
mapView.region.span.latitudeDelta *= goldenRatio
mapView.region.span.longitudeDelta *= goldenRatio
```
- 拡大(ZoomIn)するにはするけど、なぜか倍率は４倍
  - latitudeDeltaを変更したら、longitudeDeltaも自動変更されるのだろう
     - これで、２倍表示
  - longitudeDeltaを変更したら、latitudeDeltaも自動変更されるのだろう
     - これで、さらに２倍表示
  - 普通に考えたら、緯度だけ（もしくは経度だけ）を拡大縮小することは無いはず
    - 縦横（緯度経度）の縮尺が違う地図なんて使い物にならないからね

## 緯度・経度の変数値を直接変更（その２）
- その１の修正をした
- Simulator では、拡大(ZoomIn)するけど、縮小(ZoomOut)しなかった
  - 原因は知らない
  - どのように修正すれば良いのか全くわからなかった（ググれ！俺）
  - 理由なく、なんとなく、記事のように変数を作成し差し替えるように修正したら動いた

    ```swift:ViewController.swift
    var regionSpan:MKCoordinateSpan = MKCoordinateSpan()
    regionSpan.latitudeDelta = mapView.region.span.latitudeDelta * goldenRatio
    mapView.region.span = regionSpan
    ```


# 連載
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その１：プロジェクト作成）](https://qiita.com/shinobee/items/1f6d26451336bf736484)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その２：地図表示）](https://qiita.com/items/50e1acee3024c3e26fb9)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その３：位置情報取得）](https://qiita.com/items/b8d287d2e34af20aab64)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その４：位置情報と連携した地図表示）](https://qiita.com/items/a91c49ebf5301d936120)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その５：アプリアイコン設定）](https://qiita.com/items/24804294ab86635ee5d3)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その６：拡大・縮小ボタン追加）](https://qiita.com/items/12c54c4e253bc48cad4d)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その７：地図を拡大・縮小）](https://qiita.com/items/4406c4fdf2fbdcc40533)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その８：地名表示）](https://qiita.com/items/3363779d0ea11ca6073c)
1. [[はじめてのiOSアプリ]xcodeで地図アプリを作成（その９：ソースコード管理）](https://qiita.com/items/d0e63020b0dce4c70542)

<!-- eof -->