Changes to NSMetadataItem’s Attributes in iOS 9


As iOS 9 came by, two bugs appeared in an app that lets it’s users browse the app’s iCloud Drive folder from within the app itself. One related to detecting whether an NSMetadatItem is a folder or not; the other one related to whether a non-downloaded item was waiting to be downloaded.

Turned out that minor changes in NSMetadataItem´s attribute keys and values caused these bugs which were easily solved.

Folder Detection

In iOS 8 I used the NSMetadataItemContentTypeKey key in order to detect whether an NSMetadataItem was a folder or not:

+ (BOOL)isFolder:(NSMetadataItem*)item
{ 
    NSString *contentType = [item valueForAttribute:NSMetadataItemContentTypeKey];

    return contentType ? [contentType isEqualToString:(__bridge NSString *)kUTTypeFolder] : NO;
}

The kUTTypeFolder constant above corresponds to the UTI string public.folder.

In iOS 9 this no longer works and the value of NSMetadataItemContentTypeKey is not public.folder but rather strange: dyn.ah62d4vv4ge8u.
Content types for documents such as PDFs and images still return the expected values.

To fix this method in iOS 9 I used the NSMetadataItemContentTypeTreeKey key instead:

+ (BOOL)isFolder:(NSMetadataItem*)item
{ 
    NSArray *contentTypeTree = [self valueForAttribute:NSMetadataItemContentTypeTreeKey];
    APPAssertDebugKindOfClass(contentTypeTree, [NSArray class]);

    for (NSString *value in contentTypeTree) {
        if ([value isEqualToString:(__bridge NSString *)kUTTypeFolder]) {
            return YES;
        }
    }
}

In both iOS 8 and 9 NSMetadataItemContentTypeTreeKey returns an array with all UTIs the NSMetadataItem corresponds to:

kMDItemContentTypeTree = (
        "public.folder",
        "public.directory",
        "public.item"
    )

Detect if Download Has Been Requested

For each NSMetadataItem there is a certain state in which an item has been requested for download but is still waiting for download to start, i.e. the vallue for NSMetadataUbiquitousItemIsDownloadingKey is NO. To detect this one can use the NSMetadataUbiquitousItemDownloadRequestedKey, which returns a NSNumber-boxed Bool.

NSMetadataUbiquitousItemDownloadRequestedKey is not actually in the NSMetadataItem documentation, but is available in the public header together with the rest of the keys.

On iOS 8 this key is not present in the attribute dictionary so calling valueForAttribute: on NSMetadataItem on iOS 8 with this key returns nil. At least this is the case with iOS 8.4; could be that it was in fact present in earlier versions of iOS 8 (otherwise, why would I have implemented it?).

On iOS 9 however, this key is back and it works as expected. That is, if you expect the value to be YES even after the download of the NSMetadataItem has completed.

Tidbit

Also a new interesting key:

BRMetadataItemFileObjectIdentifierKey

This seems to hold an identifier for the NSMetadataItem, for example 4294989055.

Searching Google for this key gives voidness, and given the “BR” prefix — let’s leave that one alone.