Part of creating a document based application is setting up the document type and Universal Type Identifiers. However the existing documentation about this small and, imo, insufficient.

In Xcode the document types are defined above the exported and imported UTIs. But I find this to be misleading. The definition of the UTIs is, imo, more important than the document types. We should first create the necessary UTIs and then define the document types (which will refer to the UTIs).

Understanding the difference between document types and UTIs came when I realised the following: The document type relates to the application, the UTIs relate to the OS.

PS: I understand that the above is a simplification. Its just that this created an aha moment for me.

Imported UTIs

If the application can open documents that are in the public domain, i.e. existing file types, then the OS needs to know which ones. For this, we need to find the UTI of the supported file type. This can be difficult, and you may have to scourge the internet for them. Problem is that there is no central registry for UTIs.

An imported UTI refers to a file that can be opened by your application, but you are not the one who defined the layout or internal contruction of the file. For example our latest application can open JSON files, but obviously does not own the JSON file specification. Hence the JSON file type is covered by an imported UTI.

I found the JSON UTI in the plist.info of Xcode. I noticed that Xcode can open JSON files and checked its plist to see if there was a UTI defined for it. Sure enough it was: “public.json”

This is how we defined the imported UTI in our application:

imported-uti

Description: Just a description, use anything you want.

UTI: The existing UTI for the filetype the application can open.

Icon: Not necessary if the file icon image is provided in the document type or if there is no file icon image.

Conforms to: Can be used to specify a parent UTI. For JSON files this could be public.text. However I have not found this to be necessary, hence its empty.

Reference URL: Here we could have specified http://json.org, but again, it seems not be necessary and hence its empty.

Extensions: This is important, this is where the link between a UTI and a file-extension is made. In our case it should of course be json. This is a bit puzzling to me as I could imagine that the association between a UTI and file-extension would be universal, and for example on my system Xcode has this association too. But I had to enter this here otherwise the application did not want to open JSON files. So be it.

Mime Types, Pboard Types, OS Types: I believe these to be relics of the past. For legacy applications this will probably be necessary, but not for our latest application.

Note: one of the errors I made was to use an intermediate UTI (in the document type & imported-UTI) and ‘conform’ the intermediate UTI to the ‘public.json’ UTI. However that did not work!

Exported UTIs

When the application defines its own file structure, a UTI must be defined in the exported UTIs. In our application we have indeed use a file structure that we defined ourselves. It’s UTI is defined as follows:

exported-uti

Description: Just a description, use anything you want.

Identifier: The UTI for the file structure the application defines. I do not know why it is called an Identifier, but this is in fact the UTI. Apple recommends using reverse domain name identifiers.

Icon: Not necessary if the file icon image is provided in the document type or if there is no file icon image.

Conforms to: Can be used to specify a parent UTI. It is probably best to conform to at least one parent UTI, the most general of all being the public.data UTI.

Reference URL: The afsf file format is -for now- proprietary, hence no reference URL exists.

Extensions: Again, this is where the link between the UTI and a file-extension is made. In our case we use the file extension afsf (after doing some research and making sure there does not seem to be any conflict with existing file extensions).

Mime Types, Pboard Types, OS Types: I believe these to be relics of the past. For legacy applications this will probably be necessary, but not for our latest application.

Document types

Now that the necessary UTIs are known to the OS, we can specify which document types the application can handle. For our application the two document types are defined as:

document-types

Name: Of descriptive value only, use anything you like.

Class: The name of the document class that must be created and associated with the document when opened. In our case both the afsf and json files are opened by the same document class. Even though the files have completely different structures.

Extensions: I have had nothing but trouble when using these fields. Hence we use the UTIs to associate a UTI with a file extension and left these fields empty.

Icon: When an icon set is available, specify its name here. May be empty.

Identifier: Agan apple uses the generic ‘Identifier’ label, actually this is where the link between a document type and a UTI is made. For imported UTIs this field should refer to the public UTI for the file type (i.e. do not use an intermediate UTI)

Role: Refers to the capability of the application for that document type. For exported UTIs it should probably always be ‘Editor’, for imported UTIs it could also be ‘Viewer’.

Mime Types: I have not looked into this field, it may be for backwards compatibility. We did not use it.

After the definition of the UTIs these fields are self-explanatory with the following additions:

Source code

There is an impact on the source code as well. The operation:

func read(from data: Data, ofType typeName: String) throws

now no longer uses the file extension name for the typeName, but the UTI. In our document class, which can open files of two types, we have to differentiate between the typeName’s ‘public.json’ and ‘nl.balancingrock.afsf’.

Other information sources:

The above is certainly not an exhaustive treatise on the subject. When researching this subject I found the following links to be helpfull:

Apples (outdated, but only?) documentation on Uniform Type Identifiers

Apple’s list of System-Declared Uniform Type Identifiers

A github project (UITsExplorer) that maps all UTIs on your system.

Aside from apple’s documentation, this was the most helpful blogpost I found on UTIs

This problem solving answer contains a number of very helpful terminal commands to fix problems with macOS caching of UTIs and UTI handling in general.