6

我按照 Apple Docs NSMetadataQuery 中的描述使用来搜索我的 iCloud 文件。我只有一个文件,而且我知道它的名称。我的问题是有时这个文件不存在(我猜是因为它还没有被下载)并且 NSMetadataQuery 无法找到它。

曾经尝试过强制下载,NSFileManager startDownloadingUbiquitousItemAtURL:error:但它返回了一个错误。(阅读编辑)

我的解决方案是我第一次创建文件,然后我猜它存在,我用 UIDocument 打开它。但它不可能存在,或者它可能是用户第一次打开应用程序。我不能确定这些事情。我的第一个问题是:如果 UIDocument 打开文件,这意味着它在某处找到了该文件。如果文件不存在,它如何使用该文件?

然后,第二个问题:如果我的应用程序必须管理多个文件或名称未知的文件。如果 NSMetadataQuery 不起作用,我该如何找到它们。

编辑: 如果startDownloadingUbiquitousItemAtURL应该用于开始下载文件,我怎么知道文件何时完成下载(可能带有通知)?但是,更重要的是:如果总是说(删除原始名称),我该如何下载文件?

   Error Domain=NSPOSIXErrorDomain Code=2 "The operation couldn’t be completed.
    No such file or directory" UserInfo=0x166cb0 {
    NSDescription=Unable to get real path for Path
'/private/var/mobile/Library/Mobile Documents/teamid~com~team~app/Documents/file.extension'
    }
4

3 回答 3

7

我建议对 iCloud 文件使用以下加载例程。它包括4个步骤:

  1. 一、测试iCloud是否可以访问
  2. 然后查找您的文件(查找您指定的特定文件或具有特定扩展名(如 *.txt)的所有文件,或者如果您真的不知道要查找的文件扩展名,类似NSPredicate *pred = [NSPredicate predicateWithFormat:@"NOT %K.pathExtension = '.'", NSMetadataItemFSNameKey];将返回所有文件有扩展名,如 jpg、txt、dat 等)
  3. 然后检查查询是否完成,并且
  4. 最后尝试加载文件。如果该文件不存在,请创建它。如果确实存在,请加载它。

以下是示例这四个步骤的代码:

    - (void)loadData:(NSMetadataQuery *)query {

    // (4) iCloud: the heart of the load mechanism: if texts was found, open it and put it into _document; if not create it an then put it into _document

    if ([query resultCount] == 1) {
        // found the file in iCloud
        NSMetadataItem *item = [query resultAtIndex:0];
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];

        MyTextDocument *doc = [[MyTextDocument alloc] initWithFileURL:url];
        //_document = doc;
        doc.delegate = self.viewController;
        self.viewController.document = doc;

        [doc openWithCompletionHandler:^(BOOL success) {
            if (success) {
                NSLog(@"AppDelegate: existing document opened from iCloud");
            } else {
                NSLog(@"AppDelegate: existing document failed to open from iCloud");
            }
        }];
    } else {
        // Nothing in iCloud: create a container for file and give it URL
        NSLog(@"AppDelegate: ocument not found in iCloud.");

        NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
        NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:@"Documents"] URLByAppendingPathComponent:@"text.txt"];

        MyTextDocument *doc = [[MyTextDocument alloc] initWithFileURL:ubiquitousPackage];
        //_document = doc;
        doc.delegate = self.viewController;
        self.viewController.document = doc;

        [doc saveToURL:[doc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
            NSLog(@"AppDelegate: new document save to iCloud");
            [doc openWithCompletionHandler:^(BOOL success) {
                NSLog(@"AppDelegate: new document opened from iCloud");
            }];
        }];
    }
}

- (void)queryDidFinishGathering:(NSNotification *)notification {

    // (3) if Query is finished, this will send the result (i.e. either it found our text.dat or it didn't) to the next function

    NSMetadataQuery *query = [notification object];
    [query disableUpdates];
    [query stopQuery];

    [self loadData:query];

    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
    _query = nil; // we're done with it
}

-(void)loadDocument {

    // (2) iCloud query: Looks if there exists a file called text.txt in the cloud

    NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
    _query = query;
    //SCOPE
    [query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
    //PREDICATE
    NSPredicate *pred = [NSPredicate predicateWithFormat: @"%K == %@", NSMetadataItemFSNameKey, @"text.txt"];
    [query setPredicate:pred];
    //FINISHED?
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
    [query startQuery];

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"AppDelegate: app did finish launching");
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    // Override point for customization after application launch.
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil] autorelease];
    } else {
        self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPad" bundle:nil] autorelease];
    }

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    // (1) iCloud: init

    NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
    if (ubiq) {
        NSLog(@"AppDelegate: iCloud access!");
        [self loadDocument];
    } else {
        NSLog(@"AppDelegate: No iCloud access (either you are using simulator or, if you are on your phone, you should check settings");
    }


    return YES;
}
于 2011-10-31T07:44:22.923 回答
1

edo42,你解决了这个问题吗?我已经购买了一个新的 4S 以返回 AT&T,我已经备份了我的第一个 4S,然后从新 4S 的备份中恢复,然后这发生在我身上。

  1. 当我执行 [iCloudFileURL getResource:&fileState forKey:NSURLIsUbiquitousItemKey error:&error] 时,我得到了同样的错误。

错误域 = NSPOSIXErrorDomain 代码 = 2“操作无法完成。没有这样的文件或目录” UserInfo = 0x448500 {NSDescription =无法获取路径'/private/var/mobile/Library/Mobile Documents/~UbiquitousDir的真实路径~/Documents/MyDocument.ext'

(在我的 iPad 2 上运行良好)

  1. 然后我会做 NSMetadataQuery 但它回来没有结果。(在我的 iPad 2 上可以正常查看 iCloud 上的文档)。

  2. 我检查了普遍存在的文件是否存在,但正如错误提示的那样,它不存在。

  3. 我尝试使用 [fileMgr evictUbiquitousItemAtURL:ubiquitousDocumentsDir &error] 并且确实成功了。但是当我尝试 NSMetadataQuery 时,它仍然没有结果。

希望这有助于找出两种情况下的问题。

更新:好的,我从备份中恢复的这个设备的 iCloud 确实存在问题:

  1. 我已经从 iPhone 设备中删除了我的应用程序。
  2. 我从管理存储中删除了我的应用程序的备份文件。
  3. 我什至从托管存储下的 iCloud(文档和数据)中删除了我的应用程序的文件。
  4. iCloud 文件不再存在,我在 iPad 2 上查看,它消失了。
  5. 我在 iPad 2 上启动了我的应用程序,他成功保存了一个新的 iCloud 文档。
  6. 新的 iCloud 文件显示在我的 iPhone 上。
  7. 我在我的设备上构建并运行我的应用程序,但他无法使用 NSMetadaQuery 查询下载文件。
于 2011-11-30T14:26:25.887 回答
0

我遇到了类似的问题,metadataQueryDidUpdate 和 metadataQueryDidFinishGathering 会触发,但 NSMetadataQuery 的结果将为空。在我尝试在我的设备上测试它之前,Xcode 没有告诉我一个配置文件问题,但它失败了,说我的包标识符无效(它不是)。

为我解决的问题是进入首选项并单击配置文件的全部下载按钮,然后在 Xcode 中执行清理。重建,运行,我所有的文件都出现了。检查开发人员门户以确保您的个人资料都没有被标记为无效。我的都不是,所以不需要触发它,但它可能会发生。

不完全科学,但这确实对我有用。

于 2016-07-11T11:05:34.303 回答