Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用iCloud进行应用程序数据库备份,但不同步_Ios_Sqlite_Backup_Icloud_Fmdb - Fatal编程技术网

Ios 使用iCloud进行应用程序数据库备份,但不同步

Ios 使用iCloud进行应用程序数据库备份,但不同步,ios,sqlite,backup,icloud,fmdb,Ios,Sqlite,Backup,Icloud,Fmdb,我正在寻求以有限的方式使用iCloud的建议。文档主要关注多个设备之间的同步,我不需要这些。当我说iCloud时,我也包括iCloud Drive,如果这很重要的话 我的iPhone应用程序将其数据和状态存储在一个SQLite数据库文件中,我希望将其保存到iCloud(或iCloud Drive)中以用于备份,而不是在多个设备之间同步更改。在启动时,SQLite打开数据库文件并同步使用它(我使用的是FMDB)。数据库文件应该保留在设备上,这样,如果iCloud关闭,SQLite就不会知道或在意。

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

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

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

我不同步是因为共享整个SQLite文件存在数据完整性风险,而且我无法转换为核心数据(这是一个使用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数据库文件保存在文档中,但我将卷影副本写入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");
        }
    }];
}
现在我的问题是:

  • 我已经在Xcode中创建了一个自定义容器,该容器出现在我的授权文件和开发门户中,用于应用程序ID。我可以从我的两台设备(iPhone和iPad)中的任何一台将文档保存到iCloud。但是,我的两台设备看不到对方的文件。关于这一点,有许多旧的思路和随机的解决方案,但都没有解决这个问题

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


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

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

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

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

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

    - (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];
    }
    

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