【问题标题】:NSMetadataQuery doesn't find iCloud filesNSMetadataQuery 找不到 iCloud 文件
【发布时间】:2011-12-18 13:05:08
【问题描述】:

我使用 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'
    }

【问题讨论】:

    标签: objective-c cocoa icloud


    【解决方案1】:

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

    1. 首先,测试 iCloud 是否可以访问
    2. 然后查找您的文件(查找您指定的特定文件或具有特定扩展名(例如 *.txt)的所有文件,或者如果您真的不知道要查找的文件扩展名,例如 @ 987654321@ 将返回所有具有扩展名的文件,例如 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;
    }
    

    【讨论】:

    • 我已经这样做了。当我开始使用 iCloud 时,我做的第一件事就是阅读你所有的帖子。
    • 在那种情况下,我想我不太明白你的问题。您有一个可能存在或不存在的文件(例如“theFile.txt”)。使用上面的代码可以搜索theFile.txt;如果它不存在,它将创建它。如果确实存在,它将加载它。
    • 该文件不存在,我在设备 1 上创建它。然后我打开它,进行一些更改并关闭。然后我在设备 2 上打开应用程序,它有时会找到文件,有时却找不到。
    • 找到问题了!!我在另一部分代码中使用了文件协调器,我猜这给 UIDocument 文件协调器带来了一些麻烦。
    • 我在开发我的应用程序并一遍又一遍地测试我的应用程序 iCloud 设置屏幕时遇到了同样的错误,方法是从设备和我的 Mac 中删除文件,我以某种方式损坏了文件存储iCloud,所以我不得不遍历 ubiquitous 文件夹中的文件并从两个设备上手动删除它,然后删除应用程序,删除设置 /icloud /manage docs/Myapp 中可能显示的任何内容,然后在两个设备上重新安装开发应用程序,然后一切都重新开始了。祝其他遇到此问题的人好运。
    【解决方案2】:

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

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

    Error Domain=NSPOSIXErrorDomain Code=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 查询下载文件。

    【讨论】:

    • 从备份恢复后我注意到的一件事是我的应用程序不是我几天前在设备上运行的编译版本。所以我编译了最新的,现在得到了这个。
    • 在驱逐了无处不在的文档目录后,我删除了文档目录和无处不在的目录,但仍然无法在 iCloud 上下载文件。
    • 该文件也在设置/存储和备份/管理存储/文档和数据中的 iCloud 下显示。
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 2013-12-16
      • 2015-11-17
      • 2014-01-30
      • 2018-04-21
      • 1970-01-01
      • 1970-01-01
      • 2014-10-10
      • 1970-01-01
      相关资源
      最近更新 更多