我正在寻求有关以有限方式使用 iCloud 的建议。这些文档的重点是在多个设备之间同步,这是我不需要的。当我说 iCloud 时,我还包括 iCloud Drive(如果这很重要的话)。
我的 iPhone 应用程序将其数据和状态存储在单个 SQLite 数据库文件中,我希望将其保存到 iCloud(或 iCloud Drive)以进行备份,而不是用于在多个设备之间同步更改。启动时,SQLite 打开数据库文件并同步使用它(我使用的是 FMDB)。数据库文件应保留在设备上,因此,如果 iCloud 关闭,SQLite 不会知道或关心。 iCloud 会有一个卷影副本。
iCloud 副本并不总是需要最新的——我可以以编程方式启动 iCloud 更新,并在必要时进行恢复。如果本地数据库文件损坏或者用户删除了应用程序,我会从 iCloud 恢复该文件。该文件通常小于 1 MB,但也可能很大 (100 MB),但大多不变。
由于共享整个 SQLite 文件存在数据完整性风险,我没有同步,而且我无法转换为核心数据(这是一个使用 FMDB 的大型应用程序)。
我知道 iOS 每天都会备份到 iCloud,如果我可以从 iCloud(而不是整个设备)恢复我的应用程序就足够了。
我需要有关使用 iCloud 进行影子备份和恢复(但不同步)的建议。
更新:我在这个问题上取得了进展;我可以将真实的 SQLite 文件保存到 iCloud 或从 iCloud 恢复。我对 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");
}
}];
}
现在我的问题是:
我已在 Xcode 中创建了一个自定义容器,该容器出现在我的权利文件和 App 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 文档目录,则如果该目录不存在,写入将会失败。 每次都创建它会更容易,因此:
- (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];
}
关于ios - 使用 iCloud 进行应用程序数据库备份,但不同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57651344/