Adopting Uniform Type Identifiers

This chapter gives some guidelines for adopting uniform type identifiers in your application, and gives an overview of the utility functions used to manipulate UTIs.

Guidelines for UTI Usage

Adopting UTIs in your application is a two-part process. You should use UTIs whenever you need to identify or exchange data, and you should declare specific UTIs for any proprietary types your application uses.

Adding UTI Support to OS X Applications

Apple uses UTIs throughout OS X. For example: building in UTI support for most data-interchange needs. For example, the following technologies all support UTIs:

  • The Pasteboard Manager and Translation Services use UTIs to identify data types.

  • Navigation Services allows you to specify UTIs for file filtering.

  • Launch Services supports UTI-based document claims.

  • NSView and NSWindow support UTI-based drag-and-drop promises.

  • NSDocument, NSOpenPanel, NSSavePanel, and NSWorkspace all support UTIs.

  • NSSound, NSImage and NSImageRep use UTIs to return supported data formats.

Further, Apple has deprecated most older mechanisms for identifying data in favor of UTIs.

If you have specific needs that are not addressed by the above, you can match types to UTIs in your own code. Typically this requires you to find a type with an alternate identifier (such as an OSType), create a UTI from that identifier, then check for conformance with UTIs defining the types your application can handle. For an example of how to do this, see Navigation Services Tasks in Navigation Services Programming Guide.

Adding UTI Support to iOS Applications

iOS applications use UTIs to represent pasteboard types. For more information, see UIPasteboard Class Reference.

An Overview of UTI Functions

You can find the functions used to manipulate UTIs in UTType.h in the Launch Services framework on OS X and the MobileCoreServices framework on iOS.

Testing for Equality and Conformance

When testing to see if two UTIs are identical, you should always use the UTTypeEqual function rather than direct string comparison:

Boolean UTTypeEqual (
        CFStringRef inUTI1,
        CFStringRef inUTI2
    );

The two UTIs are equal if

  • the UTI strings are identical

  • a dynamic identifier’s tag specification is a subset of the other UTI’s tag specification.

However, in many cases you want to determine whether one UTI is compatible with another, in which case you should check for conformance rather than equality:

Boolean UTTypeConformsTo (
        CFStringRef inUTI1,
        CFStringRef inUTI2
    );

The UTTypeConformsTo function returns true if inUTI1 conforms to inUTI2. Conformance relationships are transitive: if A conforms to B, and B conforms to C, then A conforms to C.

Manipulating Tags

Often to use UTIs effectively, you must be able to convert various other type identifiers (OSType, MIME, and so on) to UTIs and vice versa.

To convert an identifier to a UTI, you can use the UTTypeCreatePreferredIdentifierForTag function:

CFStringRef UTTypeCreatePreferredIdentifierForTag(
        CFStringRef inTagClass,
        CFStringRef inTag,
        CFStringRef inConformingToUTI
    );

For the tag class, you pass one of the following tag class constants that define the alternate identifiers:

const CFStringRef kUTTagClassFilenameExtension;
const CFStringRef kUTTagClassMIMEType;
const CFStringRef kUTTagClassNSPboardType;
const CFStringRef kUTTagClassOSType;

You can pass a UTI in the inConformingToUTI parameter as a hint, in case the given tag appears in more than one UTI declaration. For example, if you know that the filename extension tag is associated with a file, not a directory, you can pass public.data here, which causes the function to ignore any types with the same extension that conform to public.directory. Pass NULL for this parameter if you have no hints.

In the rare case that two or more types exist that have the same identifier, this function prefers public UTIs over others. If no declared UTI exists for the identifier, UTTypeCreatePreferredIdentifierForTag creates and returns a dynamic identifier.

If you want to obtain all the UTIs that correspond to a given identifier, you can call UTTypeCreateAllIdentifiersForTag:

CFArrayRef UTTypeCreateAllIdentifiersForTag(
    CFStringRef inTagClass,
    CFStringRef inTag,
    CFStringRef inConformingToUTI );

This function returns an array of UTIs that you can examine to determine which one to use.

If you want to create an alternate identifier from a UTI, you call the UTTypeCopyPreferredTagWithClass function:

CFStringRef UTTypeCopyPreferredTagWithClass(
    CFStringRef inUTI,
    CFStringRef inTagClass );

The preferred tag is the first one listed in the tag specification array for a given tag class.

Converting OSType Identifiers

The UTI utility functions assume that all alternate identifier tags can be represented as Core Foundation strings. However, because type OSType is integer-based rather than string-based, it may not be immediately obvious how to correctly translate between type CFStringRef and type OSType. To ensure error-free encoding and decoding of OSType identifiers, use the following conversion functions:

CFStringRef UTCreateStringForOSType( OSType inOSType );
 
OSType UTGetOSTypeFromString( CFStringRef inTag );

Accessing UTI Information

To obtain a copy of a UTI’s declaration, use the UTTCopyDeclaration function:

CFDictionaryRef UTTypeCopyDeclaration(
    CFStringRef inUTI );

To obtain a URL to the bundle that contains the declaration for a given UTI, use the UTTypeCopyDeclaringBundleURL function:

CFURLRef UTTypeCopyDeclaringBundleURL(
    CFStringRef inUTI );

To obtain the localized description of a given UTI, call the UTTypeCopyDescription function:

CFStringRef UTTypeCopyDescription(
    CFStringRef inUTI );