Returning a Directory List Using NSMetadataQuery and NSPredicate

I am trying to get a list of directories in a user's iCloud folder. I developed how to search for special file types (e.g. txt files) and it works great:

NSMetadataQuery *query = [[NSMetadataQuery alloc] init]; _query = query; //Search all files in the Documents directories of the application's iCloud container directories: [query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]]; NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K ENDSWITH '.txt'", NSMetadataItemFSNameKey]; [query setPredicate:pred]; [query startQuery]; 

However, now I am trying to get only directories. I have read the docs regarding NSPredicate , but I don’t know how to look for directories. Probably NSPredicate is not for this? I can check if there is anything in this directory:

  BOOL isDir; BOOL exists = [fm fileExistsAtPath:path isDirectory:&isDir]; if (exists) { /* file exists */ if (isDir) { /* file is a directory */ } } 

But how to apply this to NSMetadataQuery, I have no idea. I would be grateful for any help I can get.


EDIT:

I changed the predicate to [NSPredicate predicateWithFormat:@"%K.pathExtension = ''", NSMetadataItemFSNameKey];

Then I determine when the request is completed as follows:

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query]; [query startQuery]; - (void)queryDidFinishGathering:(NSNotification *)notification { NSMetadataQuery *query = [notification object]; [query disableUpdates]; // You should invoke this method before iterating over query results that could change due to live updates. [query stopQuery]; // You would call this function to stop a query that is generating too many results to be useful but still want to access the available results. [self loadData:query]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query]; _query = nil; // we're done with it } 

And finally, I do the counting, but it will always give me 0, however I have several directories in the cloud (I checked this through Lion and the Mobile Documents folder, for example, I have documents / myTXT, etc.). It is very strange. If I do a text file count, it will give me 4, since I have 4 txt files. Therefore, I think my directories are not counted:

  - (void)loadData:(NSMetadataQuery *)query { NSLog(@"Query count %i", [query resultCount]); ... 
+2
source share
4 answers

I tried to answer EmptyStack with no luck ....

I found that NSMetadataQuery does NOT find directories . The problem is not that NSPredicate is filtering directories from the results, the problem is that the query does not find the folder. I tried with a debugger and found that all LBItem found were normal files, not directories. I hope Apple improves this in the future. Perhaps MountainLion is better because they seem to have folder support ... oops off course you haven't read it here because it is still an NDA. Forget about it

However, there is at least one way to work with this:

For example, if your file structure is:

 |_Folder | |_file | |_file2 |_Folder1 | |_file |_file 

and we make a request with a predicate:

 predicateWithFormat:@"%K LIKE '*'", NSMetadataItemFSNameKey 

the results will be (use NSMetadataItemURLKey to get the url)

 path/to/iCloud/Documents/Folder/file path/to/iCloud/Documents/Folder/file2 path/to/iCloud/Documents/Folder1/file path/to/iCloud/Documents/file 

We need to filter these results ourselves by looking at the number of components of each URL and breaking down the URLs as needed. Elements on the first level should have numberOfComponentsOfUbiquitousContainer + 1 , the next level will have one more, etc. We also need to undo the repetitions (or, as in this example, we will get the Folder twice).

Probably not optimal, but works for me,

Update:

It is better to use a predicate below, it reduces the query results when crawling subfolders.

 // dirPath is an NSString path of the directory you want // to look at. Usually, for the top level directory: // [NSFileManager URLForUbiquityContainerIdentifier:nil].path; predicateWithFormat:@"%K BEGINSWITH %@", NSMetadataItemPathKey, dirPath]; 
+5
source

If you want to get only directories, use the following predicate.

 predicateWithFormat:@"%K.pathExtension = ''", NSMetadataItemFSNameKey 

Note that this does not guarantee that you will only get directories using this method, since there are (I saw some) files that do not have extensions. But if you are sure that all your files have extensions, you can use this very well.

If you want to get all the files regardless of their extension, just add the NOT keyword to the above predicate,

 predicateWithFormat:@"NOT %K.pathExtension = ''", NSMetadataItemFSNameKey 
+1
source

Try the following:

 [query setPredicate:[NSPredicate predicateWithFormat:@"%K like '*.txt'", NSMetadataItemFSNameKey]]; 

This works for me.

0
source

You can do this with MDQuery - which is the "real" code that uses NSMetadataquery.

In the terminal, enter "mdls", then drag the folder. Then enter mdfind and use the above example, change the tree like kMDItemContentType to public.folder - you will get many results.

Then, to do this in code, you need to follow the MDQueryRef example. The code flow is identical to Cocoa stuff, and I find that queries are much easier to create and understand. You can set Cocoa callbacks in MDQuery - so its pretty nice drop is compatible with NSMetadataquery.

NSMetadataQuery has some iCloud elements that, it seems to me, are not in MDQuery. Therefore, I think they are not identical.

0
source

Source: https://habr.com/ru/post/899966/


All Articles