[英]How to use iCloud to store and sync app files
我已经有一个 iPhone 应用程序,可以将数据存储在本地文档文件夹中的文件中。 现在我了解了 iCloud 技术,我的第一个问题是:当我有时检查新版本时,有没有办法将 iCloud 用作目录?
我的意思是:我可以避免使用 UIDocument、文件协调器和文件展示器吗? 我只想知道是否可以将 iCloud 视为一个特殊的文件夹,并且只使用 NSFileManager 来推送和检索文件。
最后一点:我不使用 Core Data 或任何数据库,我只有一个数据文件。
编辑:
我已经阅读了 Apple iCloud 官方文档,所以不要将我链接到它们。 我只需要一些代码示例。
对我来说“有效”的方法很简单:
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq == nil) {
return NO;
}
NSError *theError = nil;
[fm setUbiquitous:true itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:backupName] error:&theError];
Apple 说要调用非 UI 线程。 让文件“移动”。 您可以通过NSMetaDataQuery
查询它们,如下所示:
self.query = [[NSMetadataQuery alloc] init];
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K like '*.db'", NSMetadataItemFSNameKey];
[self.query setPredicate:pred];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];
[self.query startQuery];
- (void)queryDidFinishGathering:(NSNotification *)notification {
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
[self loadData:query];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
self.query = nil;
}
通过查询结果进行枚举的示例:
- (void)loadData:(NSMetadataQuery *)query {
[self.backups removeAllObjects];
for (NSMetadataItem *item in [query results]) {
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
[self.backups addObject:url.lastPathComponent];
}
[_table reloadData];
[self.loadingBackupIndicator stopAnimating];
self.loadingIndicatorLabel.text = [NSString stringWithFormat: @"%d backups found", [self.backups count]];
}
并开始“下载”具体文件:
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq == nil) {
return NO;
}
NSError *theError = nil;
bool started = [fm startDownloadingUbiquitousItemAtURL:[[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:backupName] error:&theError];
NSLog(@"started download for %@ %d", backupName, started);
if (theError != nil) {
NSLog(@"iCloud error: %@", [theError localizedDescription]);
}
检查文件“正在下载”:
- (BOOL)downloadFileIfNotAvailable {
NSNumber *isIniCloud = nil;
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSURL *file = [[ubiq URLByAppendingPathComponent:@"Documents" isDirectory:true] URLByAppendingPathComponent:self.backupName];
if ([file getResourceValue:&isIniCloud forKey:NSURLIsUbiquitousItemKey error:nil]) {
// If the item is in iCloud, see if it is downloaded.
if ([isIniCloud boolValue]) {
NSNumber* isDownloaded = nil;
if ([file getResourceValue:&isDownloaded forKey:NSURLUbiquitousItemIsDownloadedKey error:nil]) {
if ([isDownloaded boolValue]) {
[self.loadingBackupIndicator stopAnimating];
self.loadingIndicatorLabel.text = @"Downloaded";
....
[[NSFileManager defaultManager] copyItemAtPath:[file path] toPath:restorePath error:&theError ];
....
return YES;
}
self.loadingCheckTimer = [NSTimer timerWithTimeInterval:3.0f target:self selector:@selector(downloadFileIfNotAvailable) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:self.loadingCheckTimer forMode:NSDefaultRunLoopMode];
return NO;
}
}
}
return YES;
}
我没想到代码这么长,很抱歉在这里提供了非常原始的片段。 无意说以上可以是代码的生产质量,只是分享概念。
我还没有在我的应用程序中将它提交给 Apple,所以不能说它会被“批准”到应用程序商店(如果他们发现或关心......)
我知道你的感受,iCloud 有点令人生畏。 但是,我认为没有办法绕过 UIDocument、文件协调器等,而只能将 iCloud 用作一个简单的文件夹。
如果您正在寻找易于理解的示例代码,请查看这篇文章:
我包含了一个完整的示例代码,它涵盖了 iCloud 的最低要求,并且几乎像目录一样使用它。 也许这会让你使用 UIDocument、文件协调器等不那么令人生畏。
但是,像你一样,我希望有一种更简单、更兼容的方式来与旧的纪录片文件夹想法相匹配。 但是,由于这是 iCloud,并且 iCloud 还做了几件事(例如在不同设备上保持所有内容同步,不断更新到云等),因此将无法绕过 UIDocument 等。
没有真正的方法可以使用 UIDocument。 我尝试在我第一次使用 iCloud 时做到这一点,但结果证明没有 UIDocument 是一场灾难。 一开始使用 UIDocument 似乎有很多额外的工作,但事实并非如此。
您可以在一个小时内轻松地将 UIDocument 子类化,并使其适用于任何类型的文件(只需将content
属性设置为 NSData)。 与标准文件系统相比,它还提供了许多好处:
老实说,花一两个小时阅读 Apple 文档然后使用它是非常值得的。 可以在Apple 的开发人员文档 中找到有关 iCloud 文档存储的优秀入门文章。
我编写了一个 UIDocument 子类,它可以处理任何类型的文件(特别是 NSData)。 您可以在GitHub 上查看、下载和修改 UIDocument 子类的代码。
创建文档:
// Initialize a document with a valid file path
iCloudDocument *document = [[iCloudDocument alloc] initWithFileURL:fileURL];
// Set the content of the document
document.contents = content;
// Increment the change count
[document updateChangeCount:UIDocumentChangeDone];
保存现有文档:
// Save and close the document
[document closeWithCompletionHandler:nil];
保存新文档:
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:nil];
您还可以使用 NSMetadataQuery 同步存储在 iCloud 中的所有文件。 Apple 提供了一个使用 NSMetadata 查询来同步应用程序文件的非常好的示例。 还要确保在执行这些操作之前检查 iCloud(提示:在 NSFileManager 上使用ubiquityIdentityToken
方法)。
您可能还需要考虑使用开源库,例如iCloud Document Sync 。 iCloud 文档同步项目使存储和同步应用程序文件变得非常容易:
用一行代码的方式将 iCloud 集成到 iOS 文档项目中。 快速轻松地从 iCloud 同步、上传、管理和删除文档。 也有助于使 iCloud 对开发人员“正常工作”。
在几乎所有 iCloud 文档同步方法中,您所要做的就是将文件数据作为参数传递,然后它会处理其余的(保存、同步等)。
免责声明:我是开源项目 iCloud 文档同步的贡献开发人员。 但是,我相信这个项目会对您有所帮助,并且与这个问题相关。 这不是促销或广告。
使用此代码:
+ (NSString *)Pathsave {
NSString *os5 = @"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedAscending) {
// Lower than 4
return path;
} else if ([currSysVer compare:os5 options:NSNumericSearch] == NSOrderedDescending) {
// 5.0.1 and above
return path;
} else {
// iOS 5
path = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
return path;
}
return nil;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.