35

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

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

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

编辑:

我已经阅读了 Apple iCloud 官方文档,所以不要将我链接到它们。我只需要一些代码示例。

4

5 回答 5

26

对我来说“有效”的东西很简单:

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,所以不能说它会被应用程序商店“批准”(如果他们发现或关心......)

于 2011-12-04T22:28:09.850 回答
17

我知道你的感受,iCloud 有点吓人。但是,我认为 UIDocument、文件协调器等没有办法简单地使用 iCloud 作为一个简单的文件夹。

如果您正在寻找易于理解的示例代码,请查看此帖子:

iCloud 基础知识和代码示例

我包含了一个完整的示例代码,它涵盖了 iCloud 的最低限度,并且几乎像目录一样使用它。也许这让您使用 UIDocument、文件协调器等变得不那么令人生畏。

但是,像你一样,我希望有一种更简单、更兼容的方式与旧的文档文件夹的想法。然而,由于这是 iCloud,而且 iCloud 做了更多的事情(比如在不同的设备上保持一切同步,不断更新到云等),所以没有办法绕过 UIDocument 等。

于 2011-10-22T09:45:34.440 回答
14

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

NSURL *destinationURL = [self.ubiquitousURL URLByAppendingPathComponent:@"Documents/image.jpg"]
[[NSFileManager defaultManager] setUbiquitous:YES 
                                    itemAtURL:sourceURL
                               destinationURL:destinationURL
                                        error:&error]
于 2012-02-07T22:46:33.637 回答
8

真的没有办法使用 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(提示:使用ubiquityIdentityTokenNSFileManager 上的方法)。


您可能还需要考虑使用开源库,例如iCloud Document Sync。iCloud Document Sync 项目使存储和同步应用程序文件变得非常容易:

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

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

免责声明:我是开源项目 iCloud Document Sync 的贡献开发人员。但是,我相信这个项目会对您有益,并且与这个问题相关。这不是促销或广告。

于 2013-11-16T16:28:45.427 回答
-1

使用此代码:

+ (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;
}
于 2013-05-22T07:01:37.670 回答