Categories
MobileCoreServices Swift

Uniform Type Identifiers on iOS

UTIs come up pretty quickly when working with files. Unfortunately APIs used for checking for conformance and creating UTIs is pretty old and does not fit well into Swift ecosystem.

Uniform Type Identifiers

Uniform type identifiers define abstract data types what can be used to describe the type of an entity. Entities include pasteboard data, files, bundles, frameworks, symbolic links and more. The full list of different data types can be found here. Some examples include:

  • kUTTypePDF (com.adobe.pdf)
  • kUTTypeJPEG (public.jpeg)
  • kUTTypeVideo (public video)
  • kUTTypeAudiovisualContent (public.audiovisual-content)

The first two are concrete types, public video is a type for video without audio and conforms also to a movie type. Audio visual content is even more generic conforming to public.data and public.content. In summary, types can create a hierarchical inheritance. Therefore instead of comparing we need to look into conformance.

Another term what comes up with UTIs are tags. Tags are another way of identifying uniform type identifiers. Tags are grouped by tag classes. Probably the best known example of a tag class is path extension of a file. Tag in this case is specific extension (pdf, txt etc).

Struct wrapping UTI functions

MobileCoreServices contains a long list of type identifiers and I think it does not make sense to redefine the whole list. What we can do instead is to define the ones we really need as static variables (alternative implementation could use enum as a base type). Two initialisers is all what we need, one for initialising using predefined identifier string and another one for initialising using tag class and tag. In addition to initialisers, separate function for checking conformance is also needed.

import MobileCoreServices
struct UTI {
let identifier: String
init(identifier: CFString) {
self.identifier = identifier as String
}
init(tagClass: CFString, tag: String) {
let preferred = UTTypeCreatePreferredIdentifierForTag(tagClass, tag as CFString, nil)
identifier = preferred!.takeRetainedValue() as String
}
func conforms(to uti: UTI) -> Bool {
return UTTypeConformsTo(identifier as CFString, uti.identifier as CFString)
}
static let pdf = UTI(identifier: kUTTypePDF)
static let text = UTI(identifier: kUTTypeText)
}
view raw UTI.swift hosted with ❤ by GitHub

When working with files, we can add a property to URL. This makes simple to detect the UTI of an URL. It should be noted that this returns preferred UTI and not all the UTIs the path extension belongs to.

extension URL {
var uti: UTI {
return UTI(tagClass: kUTTagClassFilenameExtension, tag: pathExtension)
}
}
let uti = UTI(tagClass: kUTTagClassFilenameExtension, tag: "pdf")
let isPDF = uti.conforms(to: .pdf)
view raw URL+UTI.swift hosted with ❤ by GitHub

Summary

Knowing about uniform type identifiers is needed when working with files. Unfortunately APIs interacting with UTIs are pretty old and a bit difficult to use in Swift. Therefore it is preferred to use a lightweight wrapper around the UTI functions.

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.

Resources