Swift未経験者が1日でアプリを作った話

こんにちは、前回投稿から相当時間が空いているのでたぶん初投稿です。

なんかアプリを作ることになってしまったんですが1日でできてしまったのでそのことを書いてみます。

# ～前日譚～

えらいひと「iPhoneのGPSの精度わかんないし調べようよ」
ぼく「アプリつくるんですか」
えらいひと「つくっちゃお、Mac借りてくるから」
～数日後～
社内ITのひと「Mac持ってきました」
ぼく「は～い」(マジで作るんかSwiftやったことないぞ)

# 構成図
![swift01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/f2bff1b3-942d-d1a7-0c65-fe8c07112415.png)

端末からGPSの座標を取得してAzure上にデプロイしたAPIへPOSTする単純なアプリです。

## いざ開発

といいつつも日ごろから触ってない環境で触ったこともない言語で一寸先は闇。困ったときはGoogle先生に頼ります。

### Xcodeを入れる

Xcode入れるとiOSアプリ作れるんやね。入れたる。

### プロジェクトを作る

<img width="499" alt="スクリーンショット 2019-11-28 17.19.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/7088e4d8-74a8-de7b-3137-40b2ca6e0871.png">

`Create a new Xcode project` っと。

<img width="731" alt="スクリーンショット 2019-11-28 17.21.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/b20de769-0119-33ee-c25f-d460b82cedcf.png">

なにこれ…とりあえず機能多くないし `Single View App` でいいか

![スクリーンショット 2019-11-28 17.23.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/abb42072-7dfe-f57e-42b6-36dd573aa2a0.png)

アプリの情報適当に入れてええか。`Next` 押して保存場所選択するとええな。

## 詰む

`User Interface` が `Swift UI` になっててGoogleに聞けども聞けども噛み合いません。
天の神に聞いたら
「`Storyboard` 選べ」
とのこと。

なるほど、`Storyboard` で作るとGoogleで出てくる情報通りにいくんだなと。

頼るべきは神。

## User Interface を Storyboard にして再度プロジェクト作成

ぼく「`Main.storyboard`がある！！！！！！！！！」

<img width="216" alt="スクリーンショット 2019-11-28 17.30.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/65424188-9893-7c3b-b3cd-4393acb27661.png">

`Main.storyboard` を選択するとデザイナーが出るのでUIのパーツを置いていきます。

<img width="323" alt="スクリーンショット 2019-11-28 17.32.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/b8144bd6-392f-56bc-9208-99dcb3f5093f.png">

それっぽくなってきた。

## コードを書く

天の声「`Assistant Editor`を開くとこのUIに紐づいたコードが表示されるらしい。」

なるほど。

～10分後～

いや。丸いアイコンのボタンないじゃん。

![swift02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/123667ec-2efe-b76f-6e97-44d4e100b06f.png)

天の声「どうやらXcodeのバージョンが新しくなっていてUIが変わってるらしい。」

![スクリーンショット 2019-11-28 17.40.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/775e8f50-8020-9bd0-c2a0-4862107daeb2.png)

あった。
![スクリーンショット 2019-11-28 17.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/0b625974-5832-bfe4-4d4b-6bb54aca1e30.png)

`viewDidLoad` が起動時に走る感じっぽい？
とりあえず書いていきます。

位置情報を扱うにはまずimportを追加する必要があるとな。

```swift
import CoreLocation
```

次に位置情報を司る `CLLocationManager` を初期化する必要があると。
コンストラクタに書くのも長くなるしメソッド化します。

```swift
var locationManager : CLLocationManager!

func setupLocationManager() {
    locationManager = CLLocationManager()
    guard let locationManager = locationManager
        else { return }
    
    // アプリがバックグラウンドでも位置情報を取りたいのでAlwaysAuthorizationを要求
    locationManager.requestAlwaysAuthorization()

    // 端末で位置情報取得が許可されているか取得
    let status = CLLocationManaager.authorizationStatus()

    if status == .authorizedAlways {
        locationManager.delegate = self
        locationManager.distanceFilter = 2                                    // 位置情報を再取得する閾値(m)
        locationManager.activityType = CLActivityType.automotiveNavigation    // 車での移動を想定
        locationManager.allowsBackgroundLocationUpdates = true                // バックグラウンド取得の許可
    }
}
```

こいつを起動時に呼び出してあげましょう

```swift
override func viewDidLoad() {
    super.vierDidLoad()
    setupLocationManager()
}
```

そして位置情報更新時に走る処理も作成

```swift
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = locations.first
}
```

あとはInfo.plistに位置情報要求時の文言を追記。

Keyに `NSLocationAlwaysUsageDescription` Valueに表示したい文言を追加っと。

<img width="656" alt="スクリーンショット 2019-11-28 18.10.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/9e115af0-5429-56ad-e012-7d04c9f2cf19.png">

実機で見てみますか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/e64e76ec-9715-8a44-e206-9d3b7d5c3bc9.png)

:ok: :ok: :ok: :ok: :ok: :ok: :ok: :ok: :ok: :ok: :ok: :ok: :ok: 

あとバックグラウンドでの位置情報更新を許可しないといけなかった。
プロジェクトの`Signing & Capabilities`から :heavy_check_mark: を入れましょう。

<img width="532" alt="スクリーンショット 2019-11-28 18.17.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/bbd8a6ba-880e-92db-24f9-92a5e6109d22.png">

GPSは取れたからあとはAzureに投げるだけやな！
ということで投げる部分を書きます。

```swift
func sendGeoCoordinateToWebApi(_ geo: CLLocation) {
        let url = "https://<Azure App Service名>.azurewebsites.net/api/GeoCoordinate"        
        let request = NSMutableURLRequest(url: URL(string: url)!)
        request.httpMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        // jsonを作成
        let params:[String:Any] = [                    
            "Name": textOutlet.text as String?,        
            "Latitude": geo.coordinate.latitude,       
            "Longitude": geo.coordinate.longitude,     
        ]                                              

        // POSTする
        do {                                           
            request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
            let task:URLSessionDataTask = URLSession.shared.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) -> Void in
                let resultData = String(data: data!, encoding: .utf8)!
                print(resultData)
            })
            task.resume()
        } catch {
            print("Error: \(error)")
            return
        }
    }
```

jsonを作成の部分では以下のようなjsonを作っています。作ったAPIと形式を合わせてるだけなので適当です。

```json
{
    "Name": "ワイ",
    "Latitude": 111,
    "Longitude": 111,
}
```

`textOutlet`はtextboxから値を引いてくるため設定したアウトレットです。
あとはこれを一情報更新時に発火するメソッドから呼び出すだけやな！

```swift
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = locations.first
    sendGeoCoordinateToWebApi(location)
}
```

### 完成！

早速AzureのSQL DBの中を見てみます。

![swift03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172491/1ca1beab-03bc-c309-2272-6e0bf4367a03.png)

値が入ってる～～～～～～～～～～～！！！！！！！！！！！！！！！！！！！！！！

というわけで1日(1営業日)でアプリ(と値を受け取るAPI)ができちゃいました。
おつかれさまでした。

おわり。