88242


**実現したいこと**  
RealmのオブジェクトをiCloudにアップロード、ダウンロードすることにより、スマホを紛失してもデータを復元ができるアプリデータの永続化対応

**発生している問題**  
iCloudからダウンロードしたRealmのデータをアプリで見ようとするとエラーが発生します。

**詳細なOK処理、NG処理**

① iCloudにアップロード、アプリそのままで、iCloudからデータをダウンロード、データをアプリで見る → OK  
② iCloudにアップロード、アプリをBuildでインストール、iCloudからデータをダウンロード、データをアプリで見る → OK  
③ iCloudにアップロード、アプリを手で削除してBuildでインストール、iCloudからデータをダウンロード、データをアプリで見る → NG

③が機種変をイメージしています。

今回の件はiCloudは関係なく、外部から取り込んだRealmデータを反映する箇所に問題があると思って、色々調査しましたが、わかりませんでした。  
お忙しいところ恐れ入りますが、どなたか、ご教示いただけると幸いです。

**エラーメッセージ**

[code]

    Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=2 "Unable to open a realm at path '/var/mobile/Containers/Data/Application/BA8E4840-F570-4AE0-BBA0-EF3D9B8936B0/Documents/default.realm': Realm file has bad size (181) Path:Exception backtrace:
    0   Realm                               0x00000001064c7e10 _ZN5realm15InvalidDatabaseC2ERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_ + 60
    1   Realm                               0x0000000106491c74 _ZN5realm9SlabAlloc15validate_headerEPKcmRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE + 864
    2   Realm                               0x0000000106490f28 _ZN5realm9SlabAlloc11attach_fileERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERNS0_6ConfigE + 708
    
[/code]

**ソースコード**

Class1

[code]

        private var _realm:Realm? = nil
        private var realm:Realm {
            get {
                if let realm2 = _realm {
                    return realm2
                } else {
                    let realm2 = try! Realm()     // ※※※ エラー発生位置 ※※※
                    _realm = realm2
                    return realm2
                }
            }
        }
    
[/code]

Class2

[code]

        private let _fileManager = FileManager.default
        /// バックアップフォルダURL
        private var backupFolderUrl: URL{
            get {
                return _fileManager.url(forUbiquityContainerIdentifier: nil)!
                    .appendingPathComponent("BackUp")
            }}
        /// バックアップファイル名（前部）
        private let mBackupFileNamePre = "default.realm_bk_"
        
        /// Realmのデータを復元
        func restoreRealm() {
            guard let realmURL = Realm.Configuration.defaultConfiguration.fileURL else {
                print("Realmのファイルパスが取得できませんでした。")
                return
            }
            // バックアップファイルの有無チェック
            let (exists, files) = isBackupFileExists()
            if exists {
                do {
                    let config = Realm.Configuration()
                    // 既存Realmファイル削除
                    let realmURLs = [
                        realmURL,
                        realmURL.appendingPathExtension("lock"),
                        realmURL.appendingPathExtension("note"),
                        realmURL.appendingPathExtension("management")
                    ]
                    for URL in realmURLs {
                        do {
                            try FileManager.default.removeItem(at: URL)
                        } catch {
                            print(error.localizedDescription)
                        }
                    }
                    // バックアップファイルをRealmの位置にコピー
                    try _fileManager.copyItem(at: backupFolderUrl.appendingPathComponent(files[files.count - 1]),
                                              to: realmURL)
                    Realm.Configuration.defaultConfiguration = config
                    abort()   // 既存のRealmを開放させるため
                } catch {
                    print(error.localizedDescription)
                }
            }
        }
    
        /// バックアップデータ作成処理
        /// RealmのデータをiCloudにコピー
        func backup() {
            do {
                /// iCloudにフォルダ作成
                if _fileManager.fileExists(atPath: backupFolderUrl.path) {
                } else {
                    try _fileManager.createDirectory(atPath: backupFolderUrl.path, withIntermediateDirectories: false)
                }
    
                // 既存バックアップファイル（iCloud）の削除
                deleteBackup()
                // バックアップ作成先（iCloud）
                let fileName = mBackupFileNamePre + ""   // 日付
                let fileUrl = backupFolderUrl.appendingPathComponent(fileName)
                // バックアップ作成
                try backupRealm(backupFileUrl: fileUrl)
            } catch {
                print(error.localizedDescription)
            }
        }
        
        /// Realmのデータファイルを指定ファイル名（フルパス）にコピー
        /// - Parameter backupFileUrl: 指定ファイル名（フルパス）URL
        private func backupRealm(backupFileUrl: URL) throws {
            do {
                let realm = try Realm()
                realm.beginWrite()
                try realm.writeCopy(toFile: backupFileUrl)
                realm.cancelWrite()
            } catch {
                throw error
            }
        }
        
        /// バックアップファイル削除
        func deleteBackup() {
            let (exists, files) = isBackupFileExists()
            if exists {
                do {
                    for file in files {
                        try _fileManager.removeItem(at: backupFolderUrl.appendingPathComponent(file))
                    }
                } catch {
                    print(error.localizedDescription)
                }
            }
        }
        
        /// バックアップフォルダにバックアップファイルがあるか、ある場合、そのファイル名を取得
        /// - Returns: バックアップファイルの有無、そのファイル名
        private func isBackupFileExists() -> (Bool, [String]) {
            var exists = false
            var files: [String] = []
            var allFiles: [String] = []
            // バックアップフォルダのファイル取得
            do {
                allFiles = try _fileManager.contentsOfDirectory(atPath: backupFolderUrl.path)
            } catch {
                return (exists, files)
            }
            // バックアップファイル名を選別
            for file in allFiles {
                if file.contains(mBackupFileNamePre) {
                    exists = true
                    files.append(file)
                }
            }
            return (exists, files)
        }
    
[/code]


CC BY-SA 4.0
2022-03-11T01:49:24.650
86794
2022-04-09T12:17:34.680
2022-04-09T12:10:22.073
51780
51780
question
swift realm
iCloudからダウンロードしたRealmのバックアップを用いてデータの復元


自己解決しました。  
事前に、  
FileManager.default.startDownloadingUbiquitousItem(at:)  
にて、対象ファイルと同期をとることで、正常にRealmのデータを復元できました。


CC BY-SA 4.0
2022-04-09T12:17:34.680
88242
2022-04-09T12:17:34.680
51780
86794
answer