40338


### 環境

Xcode 9.2  
Swift 4  
RealmCocoa v3.0.2  
iPhone SE Simulator 11.2

### 状況

Mastodonのクライアントを開発しています。  
OAuth関連情報の永続化が必要なため、RealmSwiftを利用してデータを永続化しようとしています。

Realmで永続化しているモデルは次の2つです。

  * InstanceModel
[code]     import Foundation

    import RealmSwift
    
    class InstanceModel: Object {
        @objc var id = UUID().uuidString
        @objc var instanceURL: String = ""
    }
    
[/code]

  * ConsumerIdModel
[code]     import Foundation

    import RealmSwift
    
    class ConsumerIdModel Object {
        @objc var id = ""
        @objc var clientId = ""
        @objc var client_secret = ""
        @objc var instanceModel : InstanceModel?
    }
    
[/code]

永続化するモデルを生成保存している部分は次のコードです。

[code]

    static func store(consumerIdStruct: ConsumerIdStruct, instanceUrl: String) {
        let instanceModel = InstanceModel()
        instanceModel.instanceURL = instanceUrl
        RealmHandler.writeInstanceModel(instanceModel: instanceModel)
        let consumerIdModel = ConsumerIdModel()
        consumerIdModel.id = consumerIdStruct.id
        consumerIdModel.clientId = consumerIdStruct.client_id
        consumerIdModel.client_secret = consumerIdStruct.client_secret
        consumerIdModel.instanceModel = instanceModel
        RealmHandler.writeConsumerIdModel(consumerIdModel: consumerIdModel)
    }
    
[/code]

永続化するモデルをRealmに書き込む処理は次のコードです。

[code]

    extension RealmHandler {
        static func writeConsumerIdModel(consumerIdModel: ConsumerIdModel) { 
            let realm = try! Realm()
            try! realm.write {
                realm.add(consumerIdModel)
            }
        }
    
        static func writeInstanceModel(instanceModel: InstanceModel) {
            let realm = try! Realm()
            try! realm.write {
                realm.add(instanceModel)
            }
        }
    }
    
[/code]

ここまでで無事永続化ができていると思っています。

このあと次のようなコードで取り出そうとすると、保存されているInstanceModelの「数」は一致するのですが、「値」が一致しません。

[code]

    extension RealmHandler {
        static func readInstanceModel(instanceUrl: String) -> InstanceModel? {
            let realm = try! Realm()
            let instances = Array(realm.objects(InstanceModel.self))
            for instance in instances {
                if instance.instanceUrl == instanceUrl {
                    return instance
                }
            }
            return nil
        }
    
        static func readConsumerIdModel(instanceModel: InstanceModel) -> ConsumerIdModel? {
            let realm = try! Realm()
            let consumerIdModels = Array(realm.objects(ConsumerIdModel.self))
            for consumerIdModel in consumerIdModels {
                if consumerIdModel.instanceModel?.id == instanceModel.id {
                    return consumerIdModel
                }
                return nil
            }
        }
    }
    
[/code]

一致しない時のデバッガログは次のようになります。  
(instanceUrlは×で置き換えておりますが、表示上は期待したインスタンスのURLが格納されています)

[code]

    (lldb) po instance
    InstanceModel {
        id = D5837160-8E32-4E56-AC79-BF220AAD00AF;
        instanceURL = ××××;
    }
    
    (lldb) po instance.id
    "FF65F00C-4F67-4E08-91CD-2607B031F945"
    
    (lldb) po instance.instanceURL
    ""
    
    (lldb)
    
[/code]

挙動を確認すると、データを参照しようとしたときに新規データとして生成されている(`UUID.uuidString`が別の値になっている)ようなので、Realmによる「取り出しデータの初期化」が完了していないように見えます。

試した解決策は次の2つです。

  * `RealmSwift.Results<>`を通常のArrayに変換する → 失敗
  * `NSThread.sleepforTimeinterval`を利用し処理を一時停止する → 失敗

おそらく初歩的なことを見落としていると思いますが、完全に頭が止まってしまいました。  
解決策をご存じの方がいらっしゃいましたらご教授いただけると幸いです。


CC BY-SA 3.0
2017-12-17T00:40:00.050
40334
2017-12-17T03:07:52.393
2017-12-17T02:50:25.500
19110
26681
question
swift ios realm
RealmCocoaで永続化したデータを取り出せない


RealmのモデルではStringやIntのプロパティは`dynamic`を指定しなければなりません。Realmはプロパティアクセスをフックして、メモリの値ではなくデータベースに保存されている値を取得するためです。Swiftでは`dynamic`を付けないと静的ディスパッチになるので、動的にプロパティアクセスをフックできません。初期値になってしまうのはそれが原因です。値は正しく保存されていて、取得だけの問題なのでモデルの定義を直せば解決します。


CC BY-SA 3.0
2017-12-17T03:07:52.393
40338
2017-12-17T03:07:52.393
5519
40334
answer