【问题标题】:Using iCloud for app database backup, but not syncing使用 iCloud 进行应用程序数据库备份,但不同步
【发布时间】:2019-12-30 06:11:02
【问题描述】:

我正在寻求有关以有限方式使用 iCloud 的建议。这些文档专注于多个设备之间的同步,我不需要。当我说 iCloud 时,我还包括 iCloud Drive,如果这很重要的话。

我的 iPhone 应用程序将其数据和状态存储在单个 SQLite 数据库文件中,我想将其保存到 iCloud(或 iCloud Drive)以进行备份,而不是用于在多个设备之间同步更改。在启动时,SQLite 打开数据库文件并同步使用它(我使用的是 FMDB)。数据库文件应该保留在设备上,因此,如果 iCloud 关闭,SQLite 不会知道或关心。 iCloud 会有一个影子副本。

iCloud 副本并不总是需要是最新的——我可以通过编程方式启动 iCloud 更新,并在必要时进行恢复。如果本地数据库文件损坏或用户删除应用程序,我会从 iCloud 恢复文件。该文件通常小于 1 MB,但可能很大 (100 MB),但大多是不变的。

由于共享整个 SQLite 文件存在数据完整性风险,我没有进行同步,而且我无法转换为 Core Data(这是一个使用 FMDB 的大型应用程序)。

我知道 iOS 每天都会对 iCloud 进行备份,如果我可以只从 iCloud(而不是整个设备)恢复我的应用程序就足够了。

我需要有关使用 iCloud 进行影子备份和恢复但不同步的建议。

更新:我在这个问题上取得了进展;我可以在 iCloud 中保存和恢复我的真实 SQLite 文件。我用这两个覆盖子类化了UIDocument

@implementation MyDocument

// Override this method to return the document data to be saved.
- (id)contentsForType:(NSString *)typeName error:(NSError * _Nullable *)outError
{
    NSString *databasePath = ... // path to my SQLite file in Documents;
    NSData *dbData = [NSData dataWithContentsOfFile: databasePath];
    return dbData; // the entire database file
}

// Override this method to load the document data into the app’s data model.
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError * _Nullable *)outError
{
    NSString *databasePath = ... // path to my SQLite file in Documents;
    NSData *dbData = contents;
    BOOL ret = [dbData writeToFile: databasePath atomically:YES];
    return YES;
}

@end

我的 SQLite 数据库文件在 Documents 中并且它保留在那里,但我因此将卷影副本写入 iCloud:

- (void)sendToICloud
{
    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];

    NSString *iCloudFileName = @"..."; // a file name I choose
    NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:@"Documents"]
                                URLByAppendingPathComponent:iCloudFileName];

    MyDocument *myDoc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];

    [myDoc saveToURL:[myDoc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
        if ( success ) {
            [myDoc closeWithCompletionHandler:^(BOOL success) {
            }];
        } else {
            NSLog(@"iCloud write Syncing FAILED with iCloud");
        }
    }];
}

现在我的问题是:

  1. 我在 Xcode 中创建了一个自定义容器,该容器显示在我的权利文件和应用 ID 的开发门户中。我可以从我的两个设备(iPhone 和 iPad)中的任何一个将文档保存到 iCloud。但是,我的两台设备看不到对方的文件。有很多关于这个的随机解决方案的旧线程,但没有解决这个问题。

  2. iCloud 文档说文件是增量更新的,但我不知道这是否适用于我的情况。如果我为MyDocument(我的iCloudFileName,上面)使用一个新文件名,我意识到一个全新的文件将被发送到iCloud。但是,如果我重用以前的文件名并每次发送更新的 NSData(就像我在 loadFromContents:ofType:error: 中所做的那样),iOS 是否只会发送自上次保存文件以来发生更改的部分?

【问题讨论】:

  • 我添加了 Swift 4 的解决方案,如果您还有任何问题,请告诉我,

标签: ios sqlite backup icloud fmdb


【解决方案1】:

现在的另一个主题是:使用 iCloud 进行跨多个设备的文件备份。

我已经解决了查看多个设备发送的 iCloud 数据的主要问题。根据 WWDC 2015 “Building Document Based App”,要查看所有文件(甚至是来自其他设备的文件),请使用 NSMetadataQuery,而不是 NSFileManager。此外,视频演示中包含有关使用 NSURL 的警告,因为文档可能会被移动(使用书签),但这不会影响我的用例。

我仍然不知道发送部分更改的 NSData 是否会导致增量更新。

我的 UIDocument 覆盖和我的 sendToICloud 方法保持不变。新功能是我的 iCloud 搜索。

如果您不写入默认的 iCloud 文档目录,则如果该目录不存在,写入将失败。 因此,每次都创建它更容易:

- (void)writeToiCloud
{
    // ...
#define UBIQUITY_ID         @"iCloud.TEAMID.bundleID.appName"
    NSFileManager *defaultManager = [NSFileManager defaultManager];
    NSURL *ubiq = [defaultManager URLForUbiquityContainerIdentifier:UBIQUITY_ID];
    NSURL *ubiquitousFolder = [ubiq URLByAppendingPathComponent:@"MyFolder"];
    [defaultManager createDirectoryAtURL:ubiquitousFolder
             withIntermediateDirectories:YES
                              attributes:nil error:nil];
    // ...
    // ... forSaveOperation:UIDocumentSaveForCreating ...
}

- (void)updateFileList
{
    // Use an iVar so query stays in scope
    // Instance variables maintain a strong reference to the objects by default
    query = [[NSMetadataQuery alloc] init];
    [query setSearchScopes:@[ // use both for testing, then only DocumentsScope
                             NSMetadataQueryUbiquitousDataScope, // not in Documents
                             NSMetadataQueryUbiquitousDocumentsScope, // in Documents
                             ]
     ];
    // add a predicate if desired to restrict the search.
    // No predicate finds everything, but Apple says:
    // a query can’t be started if ... no predicate has been specified.

    NSPredicate *predicate = [NSPredicate predicateWithFormat: @"%K like '*'", NSMetadataItemFSNameKey];
    // NSPredicate *predicate = [NSPredicate predicateWithFormat: @"%K CONTAINS %@", NSMetadataItemPathKey, @"/MyFolder/"];
    // NSPredicate *predicate = [NSPredicate predicateWithFormat: @"%K CONTAINS %@", NSMetadataItemPathKey, @"/Documents/"];
    [query setPredicate:predicate];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(queryDidFinish:)
                                                 name:NSMetadataQueryDidFinishGatheringNotification
                                               object:query];
    [query startQuery];

}

- (void)queryDidFinish:(NSNotification *)notification
{
    // iVar: NSMetadataQuery *query
    for ( NSMetadataItem *item in [query results] ) {
        NSURL *itemURL = [item valueForAttribute:NSMetadataItemURLKey];
        NSLog(@"fileName: %@",itemURL.lastPathComponent);

        // can't use getResourceValue:forKey:error
        //   that applies to URLs that represent file system resources.

        if ( [itemURL.absoluteString hasSuffix:@"/"] ) {
            continue; // skip directories
        }

        // process the itemURL here ...
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.tableView reloadData];
    });

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSMetadataQueryDidFinishGatheringNotification
                                                  object:query];
}

【讨论】:

    猜你喜欢
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    • 2014-12-26
    • 2019-04-12
    • 2015-05-14
    相关资源
    最近更新 更多