我已经有一个iPhone应用程序,该程序将数据存储在本地文档文件夹中的文件中。现在,我了解了iCloud技术,我的第一个问题是:当我有时需要检查新版本时,是否可以将iCloud用作目录?
我的意思是:我可以避免使用UIDocument,文件协调器和文件演示者吗?我只想知道是否可以将iCloud视为一个特殊文件夹,并且仅使用NSFileManager来推送和检索文件。
最后注:我不使用核心数据或任何数据库,我只有一个数据文件。
编辑:
我已经阅读了Apple iCloud官方文档,所以请不要将我链接到他们。我只需要一些代码示例。
我知道您的感觉,iCloud有点令人生畏。但是,我认为无法绕过UIDocument,文件协调器等,而只能将iCloud用作简单文件夹。
如果您正在寻找易于理解的示例代码,请查看此帖子:
我提供了完整的示例代码,其中涵盖了iCloud的最低要求,并且几乎像目录一样使用它。也许这使您不大需要使用UIDocument,文件协调器等。
但是,像你一样,我希望有一个更好的兼容旧纪录片的想法。但是,由于这是iCloud,并且由于iCloud还有其他功能(例如使所有内容在不同设备上保持同步,不断更新到云等),所以无法绕过UIDocument等。
对我来说,“有效”的方法很简单:
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,因此无法断定该应用程序将被“批准”到应用程序商店(如果他们发现或关心...)
您可以使用NSFileManager将单个文件上传到iCloud。我在博客上发布了有关如何执行此操作的complete walkthrough,但这是相关的NSFileManager代码:
NSURL *destinationURL = [self.ubiquitousURL URLByAppendingPathComponent:@"Documents/image.jpg"]
[[NSFileManager defaultManager] setUbiquitous:YES
itemAtURL:sourceURL
destinationURL:destinationURL
error:&error]
实际上没有使用UIDocument的方法。我尝试在iCloud的第一个用途中做到这一点,但是事实证明,如果没有UIDocument,这是一场灾难。首先使用UIDocument似乎需要很多额外的工作,但事实并非如此。
您可以在一个小时内轻松地将UIDocument子类化,并使其可用于任何类型的文件(只需将content
属性设置为NSData)。与标准文件系统相比,它还具有许多优点:
坦白地说,花一两个小时阅读一下Apple文档,然后使用它,这是值得的,因为它很花时间和脑力。可以在Apple's Developer Documentation中找到有关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中的所有文件。苹果公司提供了一个使用NSMetadata查询来同步应用程序文件的非常好的示例。另外,请确保在执行这些操作之前检查iCloud(提示:使用NSFileManager上的
ubiquityIdentityToken
方法)。
您可能还想考虑使用诸如iCloud Document Sync之类的开源库。 iCloud Document Sync项目使存储和同步应用程序文件变得非常容易:
使用单行代码方法将iCloud集成到iOS文档项目中。快速,轻松地从iCloud同步,上传,管理和删除文档。有助于使iCloud也“适用于开发人员”。
几乎在所有的iCloud Document Sync方法中,您要做的就是将文件数据作为参数传递,然后处理其余的数据(保存,同步等)。
DISCLAIMER
:我是开源项目iCloud Document Sync的特约开发人员。但是,我相信这个项目将对您有益,并且与此问题相关。这不是促销或广告。使用此代码:
使用此代码: