If you’ve been doing any kind of file uploads, downloads, previews, and such in past versions of Xcode and needed to deal with MIME types or file extensions, you’ve probably had to deal with Uniform Type Identifers. Using CoreServices
and some of its methods such as UTTypeCreatePreferredIdentifierForTag
and UTTypeCopyPreferredTagWithClass
could avoid some hard-coding of identifiers and such; however these methods are more difficult to work with as they involve unmanaged CFString
classes as well as iteration through tag dictionaries in some cases.
Enter the New UTType Class
With Xcode 12 and iOS 14 (macOS 11, watchOS 7, or tvOS 14 as well), we now have an awesome new Swift-based UTType
struct that abstracts a lot of the complexity out and makes life simpler when dealing with file extensions and MIME types for documents from Microsoft Office, Adobe Acrobat, or even your own custom file types. By providing properties such as preferredMimeType
, preferredFilenameExtension
, and identifier
, developers will now be able to craft code more cleanly in Swift with less effort.
For example to get the key components for an Adobe Acrobat PDF document, we can just use import UniformTypeIdentifiers
and do this.
import UniformTypeIdentifiers
let pdf: UTType = .pdf
print("MIME type: \(pdf.preferredMIMEType!)") //application/pdf
print("File Extension: \(pdf.preferredFilenameExtension!)") //pdf
print("Identifier: \(pdf.identifier)") //com.adobe.pdf
You can also infer a full UTType object from a file extension or MIME type with the static types(tag:tagClass:conformingTo:)
method as follows.
import UniformTypeIdentifiers
let word: UTType = .word
print("MIME type: \(word.preferredMIMEType!)") //application/vnd.openxmlformats-officedocument.wordprocessingml.document
print("File Extension: \(word.preferredFilenameExtension!)") //docx
print("Identifier: \(word.identifier)") //org.openxmlformats.wordprocessingml.document
extension UTType {
// Word documents are not an existing property on UTType
static var word: UTType {
// Look up the type from the file extension
UTType.types(tag: "docx", tagClass: .filenameExtension, conformingTo: nil).first!
}
}
Using UTType
with Existing Functions
Obviously it will take Apple a while to spread this new class out through all the existing areas in the app but you can still start leveraging UTType in your existing code today. Many of the existing functions that accept strings can just be altered to use the new types instead of raw, hard-coded strings or the existing UTI’s that were in CoreServices
in UTCoreTypes.h
. For example, when donating a user activity for Spotlight, it’s necessary to spin up a CSSearchableItemAttributeSet
to append thumbnails or properties such as keywords. Previously this would have resulted in some code looking like this with kUTTypeItem
in this case.
let attributes = CSSearchableItemAttributeSet(itemContentType: kUTTypeItem as String)
We can now replace that with this in iOS 14 code and possibly remove a reference to CoreServices
.
let attributes = CSSearchableItemAttributeSet(itemContentType: UTType.item.identifier)
Fortunately some existing methods are already being updated. Where you might have done something like this in the past to initialize a UIDocumentPickerViewController
for PDF and Word documents,
// Word not available in UTCoreTypes
let documentTypes = [kUTTypePDF as String, "org.openxmlformats.wordprocessingml.document"]
// Initialize document picker with the allowed types
let documentPickerViewController = UIDocumentPickerViewController(documentTypes: documentTypes, in: .import)
You can now do this with UTType
with some type safety and less hard-coding of strings using this overload of init
on UIDocumentPickerViewController
.
//PDF is a known type but word needs to be looked up
var documentTypes: [UTType] = [.pdf, .word]
let documentPickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: documentTypes)
extension UTType {
//Word documents are not an existing property on UTType
static var word: UTType {
UTType.types(tag: "docx", tagClass: .filenameExtension, conformingTo: nil).first!
}
}
What To Do Next?
So after you fix up your code and get rid of some of those old references to UTTypeCore, you might also want to check out defining your own Uniform Type Identifier, especially if your app has a custom document format that other apps can leverage.
It’s great to see Apple modernizing some of the core functionality and introducing Swift compatibility with code that’s been baked in for years. Changes like this make it easier for us as developers to move forward and write stable, maintainable code.
Get the Source
Download sample code with some of the above examples from Github.
Nice poost thanks for sharing
LikeLike