[Swift]Realm Swift #3 トラブル対応

iOS でRealm　Swift を 利用し、サンプルを作成する際のトラブル内容と対応事項をメモします。

#目次
[・ Realm Swift#1 class ](https://qiita.com/mario7/items/2df2c3e172f15f1d07cb)
[・ Realm Swift#2 sample](https://qiita.com/mario7/items/a0a6a4e4c09ce1e0986b)
・ Realm Swift#3 issue

# 動作環境
Swift 5.0
Xcode 11.1

# トラブル一覧
１。レルムにデータ追加失敗の時
２。複数カラムのプライマリーキーが作成したい場合
３。 レルム取得する際にアプリクラッシュされる場合

#レルムにデータ追加失敗の時

```StudentAccessor.swift
class Student: Object {
    @objc dynamic var studentId = ""
    @objc dynamic var name = ""
    @objc dynamic var age = 0
}
func add(obj :T) throws {
    let realm = try! Realm()
    try realm.write {
        realm.add(obj, update: .modified)
    }
}
```
下記のようにRLMExceptionエラーが起きる。　

<img width="841" alt="realm-add-exception.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/6a8d1756-1755-d144-9826-8ca2ea0c8b75.png">
__理由 ：__ `主キーが存在しないため、更新できません。`
##対応方法
##対応① <font color="BlueViolet">主キーを設定すること。</font>

[※注意：https://realm.io/docs/swift/3.20.0/#models](https://realm.io/docs/swift/3.20.0/#models)
<font color="Red">主キーを宣言すると、オブジェクトを効率的に検索および更新でき、
各値に一意性を適用できます。
主キーを持つオブジェクトをレルムに追加すると、
主キーは変更できなくなります。</font>


```StudentAccessor.swift(Primarykey)
override public static func primaryKey() -> String? {
    return "studentId"
}
```
##対応②：<font color="Magenta">主キーが設定できない場合</font>


```StudentAccessor.swift(追加のみ)
try realm.write {
    //追加の場合
    //realm.add(obj, update: .modified)
    realm.add(obj)
}
```

```StudentAccessor.swift(更新のみ)
let student = realm.getObjects.first
try realm.write {
    //更新の場合
    student?.name = "test"
    student?.age = 20
}
```
# 複数カラムの主キーが作成したい場合
```Student.swift(NG)
class Student: Object {
    @objc dynamic var studentId = ""
    @objc dynamic var age = 0
    
    override public static func primaryKey() -> String? {
        return String(format: "%@_%d ", studentId,age)
    }
```
<font color="Red">(NG) 理由:主キーは一つ項目であるため、</font>
<img width="835" alt="realm-multi-primary-key-error.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101832/51cfeb59-4e31-c5e1-9619-717e8e3b949b.png">

##対応: 主キー(customPrimaryKey)を新しく作成すること。
但し、不要な項目が追加されてしまう。

```Student.swift(OK)
class Student: Object {
    @objc dynamic var studentId = ""
    @objc dynamic var age = 0
    @objc dynamic var customPrimaryKey = ""
    
    override public static func primaryKey() -> String? {
        return "customPrimaryKey"
    }
    
    convenience init(studentId: String, age: Int) {
        self.init()
        self.studentId = studentId
        self.age = age
        self.customPrimaryKey =  String(format: "%@_%d ", studentId,age)
    }
```
# レルム取得する際にアプリクラッシュされる場合

```RealmBaseDao.swift(NG)
func updateOnly(block:() -> Void ) throws {
    try realm.write(block)
}
```
__原因 ：__ ` 想定ですが、クロージャは解放されず、
レルムのトランザクションを完了されなっかた。`
##対応：<font color="Red"> @ escaping</font>を付与すること。
・クロージャが外部から渡される場合、@ escapingが必須らしい。
・非同期処理の後にクロージャを実行する場合は、
@ escaping を引数で受け取るクロージャに付与しなければなりません。

```RealmBaseDao.swift（OK）
func updateOnly(block: @escaping () -> Void ) throws {
    try realm.write(block)
}
```

##参考
[https://realm.io/docs/swift/3.20.0/](https://realm.io/docs/swift/3.20.0/)
[@escapingと@autoclosure](https://qiita.com/rockname/items/bbdbac9aee11b3e33515)

## Index
[≪ Realm Swift #2 サンプル](https://qiita.com/mario7/items/a0a6a4e4c09ce1e0986b)