Objective c 如何使用iCloud存储和同步应用程序文件

Objective c 如何使用iCloud存储和同步应用程序文件,objective-c,cocoa-touch,nsfilemanager,icloud,Objective C,Cocoa Touch,Nsfilemanager,Icloud,我已经有了一个iPhone应用程序,它将数据存储在本地文档文件夹中的文件中。现在我了解了iCloud技术,我的第一个问题是:当我有时检查新版本时,有没有办法将iCloud用作目录 我的意思是:我可以避免使用UIDocument、文件协调器和文件演示器吗?我只是想知道是否可以将iCloud视为一个特殊的文件夹,只使用NSFileManager来推送和检索文件 最后一点:我不使用核心数据或任何数据库,我只有一个数据文件 编辑: 我已经阅读了苹果iCloud的官方文档,所以不要将我链接到它们。我只需要

我已经有了一个iPhone应用程序,它将数据存储在本地文档文件夹中的文件中。现在我了解了iCloud技术,我的第一个问题是:当我有时检查新版本时,有没有办法将iCloud用作目录

我的意思是:我可以避免使用UIDocument、文件协调器和文件演示器吗?我只是想知道是否可以将iCloud视为一个特殊的文件夹,只使用NSFileManager来推送和检索文件

最后一点:我不使用核心数据或任何数据库,我只有一个数据文件

编辑:


我已经阅读了苹果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];
苹果公司说要调用非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]);
}
检查文件“正在下载”:

我没想到代码会那么长,很抱歉在这里提供了非常原始的代码片段。没有意图说上面可以是一个产品质量的代码,只是分享了这个概念


我还没有将我的应用程序中的文件提交给苹果,因此无法判断是否会“批准”到应用程序商店(如果他们发现或关心…)

您可以使用NSFileManager将单个文件上传到iCloud。我在博客上发布了一篇关于如何做到这一点的文章,但以下是相关的NSFileManager代码:

NSURL *destinationURL = [self.ubiquitousURL URLByAppendingPathComponent:@"Documents/image.jpg"]
[[NSFileManager defaultManager] setUbiquitous:YES 
                                    itemAtURL:sourceURL
                               destinationURL:destinationURL
                                        error:&error]
使用此代码:

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

使用UIDocument真的没有办法。我第一次使用iCloud时就试着这么做,但没有UIDocument,结果是一场灾难。一开始使用UIDocument似乎需要做很多额外的工作,但事实并非如此

您可以在不到一小时的时间内轻松地将UIDocument子类化,并使其与任何类型的文件一起工作(只需将
内容
属性设置为NSData)。与标准文件系统相比,它还提供了许多好处:

  • 变更跟踪
  • 文件冲突解决
  • 文件国家支持
  • 增强的保存/打开/关闭功能
老实说,花一两个小时阅读苹果的文档,然后使用它是值得的时间和脑力。有关iCloud文档存储的入门文章,请参阅


我已经编写了一个UIDocument子类,它可以处理任何类型的文件(特别是NSData)。您可以在上查看、下载和修改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];
保存现有文档:

// 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];
保存新文档:

// 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文档同步项目使存储和同步应用程序文件变得非常容易:

使用单行代码方法将iCloud集成到iOS文档项目中。快速方便地从iCloud同步、上载、管理和删除文档。也有助于使iCloud对开发人员“正常工作”

在几乎所有的iCloud文档同步方法中,您所要做的就是将文件数据作为参数传入,然后由它处理其余部分(保存、同步等)


免责声明:我是开源项目iCloud Document Sync的贡献开发者。然而,我相信这个项目将对你有益,并且与这个问题相关。这不是促销或广告。

我同意,如果你说不行,我会阅读教程。但我认为应该有一种更简单的方法来做到这一点,比如在应用程序沙箱中编写或读取文件。感谢您注意到“生产”上面代码的版本将其在应用程序内部传递到应用程序商店。请提供包含上述代码的示例项目。如果可能,请帮助我。@StanislavDvoychenko您好,先生,请告诉我有关icloud编码部分的一些想法。指的是如何搜索和检索等。请再次感谢UrlUbiquitousItemisDownloadedKey已加载iOS7中已弃用,替换为NSURLUbiquitousItemDownloadingStatusKey。我还要感谢Stanislav发布了这样一个完整而有用的例子。我们可以通过iCloud共享链接吗?就像在Pages应用程序和Key not应用程序中一样。如何设置文件权限和所有权限并通过电子邮件共享链接,这正是我最后所做的。如果您的用例是将数据转储到iCloud,则可以使用文件协调器,而不需要UIDocument。是否有方法复制而不是移动?当我这样做时,我尝试使用residentData=[[NSMutableArray alloc]initWithContentsOfURL:icloudURL];但每次都返回nil。。