Swiftで連絡先アプリに連絡先を追加する

# はじめに
連絡先アプリから読み込みを行う記事はそこそこありましたが、連絡先を追加する記事はそんなになかったのでメモとして残しておきます。

# 環境
以下の環境で動作確認を行いました。

- Xcodeのバージョン: Xcode11.3
- Swiftのバージョン: Swift5 

# 下準備
連絡先にアクセスするためにinfo.plistに以下の項目を追加します。

| Key | Value |
| :-: | :---: |
| `Privacy - Contacts Usage Description` | 連絡先にアクセスする理由等を記述 |

これがないとエラーになるので忘れずに追加します。

# 連絡先へのアクセス許可を確認
アプリが連絡先にアクセスすることを許可してもらう必要があるので、現在の認証状態を確認してそれに応じた対応を行います。

初回の場合はいつものアクセス許可を求めるアラートを表示させたりするのが一般的だと思います。
その際にアラートを出したり、後の連絡先を保存する際に必要になる`CNContactStore`をインスタンス化させておきます。

```Swift
import Contacts

let contactStore = CNContactStore()

switch CNContactStore.authorizationStatus(for: .contacts) {
case .notDetermined, .restricted:
    contactStore.requestAccess(for: .contacts) { granted, error in
        if let error = error {
            print(error)
        }
        if granted {
            // アクセスを許可してもらえた時
        } else {
            // アラートからアクセスの許可をしてもらえなかった時
        }
    }
case .denied:
    // 拒否されている場合
case .authorized:
    // すでにアクセスが許可されている場合
default:
    // それ以外の場合
}
```

# 連絡先を追加
それでは本題です。
まずは連絡先のデータベースに保存を行うための`CNSaveRequest`と保存する連絡先の情報となる`CNMutableContact`用意します。

```Swift
import Contacts

let request = CNSaveRequest()
let contact = CNMutableContact()
```

名前や電話番号、メールアドレスなどの情報を`CNMutableContact`に入れていって、最後に`CNSaveRequest`で保存を行うような流れになります。

## 名前
名字、名前、それぞれのふりがなを指定することができます。

```Swift
contact.givenName = "名前"
contact.familyName = "名字"
contact.phoneticGivenName = "なまえ"
contact.phoneticFamilyName = "みょうじ"
```

## 組織
組織名とふりがなを指定できます。

```Swift
contact.organizationName = "組織名"
contact.phoneticOrganizationName = "そしきめい"
```

## 電話番号
電話番号は複数指定可能です。
`CNLabeledValue<CNPhoneNumber>`の配列となっていて、初期化に若干苦戦しました。

引数`label`に`CNLabelPhoneNumberMain`のような`CNLabelPhoneNumber...`となっている定数を指定すると、デフォルトで用意されている電話番号の項目用のタイトルが上につきます。`String?`なので任意の文字列を入れることも可能です。

```Swift
contact.phoneNumbers = [
    CNLabeledValue<CNPhoneNumber>(label: CNLabelPhoneNumberMain, value: CNPhoneNumber(stringValue: "123-4567-8910")),
    CNLabeledValue<CNPhoneNumber>(label: "カスタムのラベル", value: CNPhoneNumber(stringValue: "123-4567-8910"))
]
```

## メールアドレス
メールアドレスも電話番号と同じく複数指定可能です。

`CNLabelEmailAddress...`みたいなのはなかったので、`CNLabelHome`と`CNLabelWork`を指定しています。この辺はなんでもいいのかもしれません。

```Swift
contact.emailAddresses = [
    CNLabeledValue<NSString>(label: CNLabelHome, value: NSString(string: "sample@sample.com")),
    CNLabeledValue<NSString>(label: CNLabelWork, value: NSString(string: "sample@sample.com"))
]
```

## URL
これも同じく複数指定可能です。

```Swift
contact.urlAddresses = [CNLabeledValue<NSString>(label: CNLabelURLAddressHomePage, value: NSString(string: "https://www.apple.com/jp/"))]
```

## 住所
同じく複数指定可能です。
`CNMutablePostalAddress`が引数に必要になるのでインスタンス化して住所の情報を代入します。

```Swift
let address = CNMutablePostalAddress()
address.country = "日本"
address.postalCode = "460-8508"
address.state = "愛知県"
address.city = "名古屋市"
address.street = "中区三の丸3丁目1−1"

contact.postalAddresses = [CNLabeledValue<CNPostalAddress>(label: CNLabelHome, value: address)]
```

## 保存
最後に保存を行います。
`CNSaveRequest`に保存する`CNMutableContact`を追加してから保存を行います。
例外を投げるので`try catch`が必要です。

```Swift
request.add(contact, toContainerWithIdentifier: contactStore.defaultContainerIdentifier())

do {
    try contactStore.execute(request)
} catch {
    print(error)
}
```

追加された連絡先はこんな感じに表示されます。

<img width="300" alt="スクリーンショット 2020-01-07 17.39.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/202306/41ff2ef8-811c-88ad-1732-220455d21e07.png">

# さいごに
他にも`birthday`や`relation`、`socialProfiles`などを指定することができますが、とりあえずよく使いそうな項目だけ抜粋しました。

何か間違っている点などがありましたら指摘してください🙇‍♂️

# 参考にさせていただいた記事
[swift（iOS10）で連絡先アプリから連絡先データを取得する](https://qiita.com/kato-i-l/items/0d79e8dcbc15541a5b0f)