32093


iPhoneからApple WatchへRealmのデータ転送を行って、Apple Watchでデータを表示したいと思っています。

やりたいことは以下の通りです。

  * iPhoneからApple WatchへRealmのデータを転送してデータを表示したい
  * iPhoneからApple Watchにデータ転送できない場合は、Apple Watchにある（最後に転送された）Realmデータを表示
  * iPhoneとApple Watchと通信ができる時には常にiPhoneのRealmデータを転送して最新の状態にしたい

別質問で以下の内容でiPhoneからApple Watchへデータ転送ができることを確認しました。

[code]

    // When the file was received
    func session(_ session: WCSession, didReceive file: WCSessionFile) {
        //set the recieved file to default Realm file
        var config = Realm.Configuration()
    
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let documentsDirectory = paths[0]
        let realmURL = documentsDirectory.appendingPathComponent("data.realm")
        try! FileManager.default.copyItem(at: file.fileURL, to: realmURL)
    
        config.fileURL = realmURL
        Realm.Configuration.defaultConfiguration = config
    
        // display the first of realm objects
        let realm = try! Realm()
    }
    
[/code]

しかし、2回目の処理時に **try! FileManager.default.copyItem(at: file.fileURL, to:
realmURL)** で以下のエラーが確認されました。

> fatal error: 'try!' expression unexpectedly raised an error: Error  
>  Domain=NSCocoaErrorDomain Code=516 "“data.realm” couldn’t be copied to  
>  “Documents” because an item with the same name already exists."

（すでにファイルが存在しているということでエラーになっているものかと思うのですが、、）

この場合は **FileManager.default.fileExists(atPath: realmURL.absoluteString)**
でデータが存在しているかを確認して、ファイルがあれば、コピーは行わずに読み込みを行うという流れで問題ないでしょうか？  
（それともローカルにあるRealmデータを削除して、もう一度通信時に転送したパスからデータをコピーするという流れでしょうか・・・？）

また、2回目以降（Realmデータ読み込みした後の起動時）にはデータのパスから読み込みを行えば、Realmからデータを読み込むことができるのでしょうか？  
（言い換えると、 **Realm.Configuration.defaultConfiguration**
で設定したものはアプリ終了後も有効なのでしょうか？）

かなり具体的な内容ですが、わかる方がいましたらご教授いただければと思います。

よろしくお願いいたします。


CC BY-SA 3.0
2017-01-16T04:54:01.867
31880
2017-01-23T19:36:54.780
20124
question
swift ios realm watchkit
Apple WatchでのRealmのローカルデータの取り扱い方について教えてください


> しかし、2回目の処理時に try! FileManager.default.copyItem(at: file.fileURL, to:
> realmURL) で以下のエラーが確認されました。

まずここで起こっていることは、ご推察の通りで、すでに以前にコピーしたファイルが存在するために、ファイルをコピーすることに失敗した、というエラーです。ここまではRealmは関係ありません。ファイルを上書きする方法はいくつかありますが、とりあえず古いファイルが存在したら消すというのが簡単でしょう。

[code]

    if FileManager.default.fileExists(atPath: realmURL.path) {
        try! FileManager.default.removeItem(at: realmURL)
    }
    
    try! FileManager.default.copyItem(at: file.fileURL, to: realmURL)
    
[/code]

上記のようにして、すでにファイルがコピー先に存在すればそのファイルを消して、改めて転送されてきたファイルをコピーするようにします。

> この場合は FileManager.default.fileExists(atPath: realmURL.absoluteString)
> でデータが存在しているかを確認して、ファイルがあれば、コピーは行わずに読み込みを行うという流れで問題ないでしょうか？  
>  （それともローカルにあるRealmデータを削除して、もう一度通信時に転送したパスからデータをコピーするという流れでしょうか・・・？）

上記についてどちらが正しいということはなく、期待する動作が何かによります。  
期待している動作は、

> iPhoneとApple Watchと通信ができる時には常にiPhoneのRealmデータを転送して最新の状態にしたい

ということですので、ファイルが転送されてきた場合には常に既存のファイルを削除して新しいファイルをコピーして使うという動作にするべきだと思いましたので、先に述べたような方法になります。

さらに

> iPhoneからApple Watchにデータ転送できない場合は、Apple Watchにある（最後に転送された）Realmデータを表示

という要件もあるので、データ転送できなかった場合、`session(_ session: WCSession, didReceive file:
WCSessionFile)`が呼ばれなかったり、失敗のデリゲートが呼ばれた場合には、以前に転送されたファイルがあればそれを表示するべきだと思います。

> また、2回目以降（Realmデータ読み込みした後の起動時）にはデータのパスから読み込みを行えば、Realmからデータを読み込むことができるのでしょうか？  
>  （言い換えると、 Realm.Configuration.defaultConfiguration
> で設定したものはアプリ終了後も有効なのでしょうか？）

`Realm.Configuration.defaultConfiguration`の内容は当然ながらアプリケーションを終了すると失われてしまうので、起動したときに再度設定する必要があります。  
ファイルは同じ場所に存在するので、

[code]

    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    let realmURL = documentsDirectory.appendingPathComponent("data.realm")
    
[/code]

のようにして、同じようにドキュメントディレクトリを取得し、Realmファイルが保存されている場所をURLとして組み立てて渡すということをやることになります。  
ドキュメントディレクトリや、その中のRealmファイルの物理的な場所は変わりませんが、セキュリティのためにドキュメントディレクトリを示すパスは毎回変更されます。そのため、面倒でも上記のようにAPIを利用して、ドキュメントディレクトリの場所を毎回、新しく起動した時には取得し直す必要があります。


CC BY-SA 3.0
2017-01-23T19:36:54.780
32093
2017-01-23T19:36:54.780
5519
31880
answer