– creating/setting filetypes for a document-based app (whether using NSDocument or not)
– telling the system which filetypes your apps will open

On macOS, you’re more likely to encounter UTIs in the both context; the importing of files (eg images) can be handled without UTIs. The whole system of ‘opening files programmatically/using NSSavePanel/NSOpenPanel’ is both forgiving enough that you can, and confusing enough that you probaly will want to forego learning it until you’ve had some Swift development practice under your belt – you will need this to deploy to the AppStore, but you can work on your app without mastering this. If you’re like me, you’ll reach the stage where being able to double-click a file and having it open automatically would be really useful.

UTIs are not an ‘advanced’ topic in any sense of the word – they’re not complex like CoreData or Metal, they don’t even need a lot of previous knowledge. They are merely tedious, not in the least because they do not lend themselves to a lot of experimentation or incremental development, and because there are multiple parameters, it’s difficult to know which settings you should have given different values to.

0) We’ll play with Unicorns.
Create a new application, either turn sandboxing off or add ‘write and read’ to your app’s capabilities.

In 10.12; once all of this has been set up correctly, I was able to open files from the Finder even after setting file permissions to ‘none’. (NSOpenPanel, on the other hand, will crash.)

I’m going to borrow the code and setup from the ‘Saving Files with Codable’ post: create a ‘save’ button, a ‘load’ button (both with actions), an inputFld text field and an outputLabel. Add the following things to your ViewController class:

Build and run. You can write something in the input field, save it to file, check that it’s been saved to file by opening your file with TextEdit or another application, and read it in again.

Setting up DocumentTypes and Exported UTIs

1a) The next step modifies your application’s info.plist, but I’ve had no luck actually changing values there – you need to go through Target: Info and add a document type.

Name, identifier, extensions should be self-explanatory. Class does not apply here (we’re not working with NSDocument), we’re not messing with mime types. Role should be ‘Editor’ rather than ‘Viewer’.

While this example by Apple asks you to add CFBundleTypeRole as an additional property, that is the ‘Role’ above, so you can skip that step; LSHandlerRank, on the other hand, should be set to ‘Owner’ (we’re the primary creator and handler of unicorns).

You can ignore pasteboard type (up to 10.5) and mime type. If you’re using an NSDocument-based application, you need to specify your subclass of that in the ‘Class’ setting.

1b) For Exported UTIs, you want to fill out all of the obvious items: description, extensions, identifier, (leave icon alone for now, that one is more complicated than it looks at first, we deal with it later), and find the right value for ‘conforms to’. In this case, because we’re saving strings, it’s public.text; for a customary file format with our own objects, it would be public.data.

You need to add an additional property: UTTypeTagSpecification (this does not autocomplete). Change it to a Dictionary, and add a row: public.filename-extension, which needs to be an array; add one row to it, which is a String: unicorn.

If you have all of these set correctly, where ‘correct’ = ‘as detailed in the documentation linked above’, your app will finally move from

to

As you may guess from the filename, at this point I had tried this several times, checked and double-checked and disregarded the first tutorial to google again, and we have _partial_ success: the Finder knows that unicorns belong to my UTI Creation app.

1c) We’ll ignore imported UTIs, though they are a neat feature: if your application handles an uncommon filetype belonging to another application – say, WordPerfect files (.wp, .wpd), and you don’t expect that application to be present on users’ computers (AFAIK, there is no current version or variant of WordPerfect that will run on macOS), but you still want users to be able to see in the Finder that they can open the file in your app, you can define an _imported UTI_. This means you won’t save (export) that format, but you can open (import) it.

Opening Files from the Finder

Open, Unicorn

2) The problem of opening files is quite interesting in itself. Right now, our app does not have a concept of ‘opening files’. It has a method that can be pointed at a URL and which does things with that URL, but it does not have an entry point for ‘opening files’, so when the FileManager asks our app ‘can you open this file’ it just goes ‘huh?’.

This function should call on whatever function you use to open a file. If you’re using URLs in your app, convert it using URL(fileURLWithPath: filename)

One would expect, to be a good citizen, that you should return ‘true’ only when you actually opened the file, as opposed to ‘trying to open a file with the right extension’. Given how many unicorns are running around since the ‘Saving Files with Codable‘ tutorial, many with different contents (there are Strings, and NSCoding compliant, and Modern unicorns… ) this seems like a good idea. However, this ideal runs up against Swift error handling: while you can attempt return a value from the catch part of a do–try–catch block, it gets ignored; so the only thing I have found that’s possible here is to return ‘true’ whatever happens.

func application(_ sender: NSApplication, openFiles filenames: [String]) works in exactly the same manner as the single file variant, with the slight quirk that it overrides the single filename version, so you either the single filename version gets called several times in succession or you always call the multiple filenames function even if you only open one file and the other remains unused.

Why am I emphasizing ‘filename’ so much? It turns out that there is afunc application(_ application: NSApplication, open urls: [URL])
function coming up in code completion, (without a matching open url function); but using _that_ in your application gets us back to the _UTI Creation cannot open files in the “unicorn” format_ error we had before implementing application(openFile:). Turns out that the compiler was slightly asleep here: the documentation offers no advice on this method whatsoever, but tells you it’s available in 10.13+. If you’re working on 10.13, you should use the URL-based version instead of a path(string-) based method.

2b) Of interest may be two other points: an ‘untitled file’ is a new, untitled file, while ‘temporary file’ is a new file that the application is supposed to clean up (similar to opening files shared from e-mail on iOS?). I’m not certain what the use cases are. According to this StackoverflowDiscussion from 2012, the behaviour for untitled files has changed in Lion (macOS 10.7); as far as I can make out applications created (or not) new, untitled files on startup; but with the restoration of apps, it can happen that you simply re-open the new untitled document you opened the last time you opened the app, rather than creating a new one, so this method will not get called every time you start up the app. Or something. (This seems relevant only for document-based apps, and when I get around to those, I might play with this function again). Other than that, Google has returned one page of links to Apple’s documentation with a single mention elsewhere which is simply a listing of functions without explanation of what they do, so that’s gonna be a fun rabbit hole when the time comes.

Adding File icons

File Icons

3) We’re nearly there. We can now double-click files in the finder (or drag them onto the application’s dock tile, or choose ‘open’), and the Finder Info says that our app is the default app for opening .unicorn files. What we haven’t got yet is an icon for our files. This is not as straightforward as one might hope: there are fairly strict rules for icons. In fact, the rules for File icons are the same as those for Application icons – both used by the Finder – but while you can create your app icons and drop them into your Assets catalogue, this was only enabled in 10.13 for file icons (and thus, I haven’t tested it yet.) For 10.12 or lower, you need to create a special folder containing all of your resolutions.

3a) First, hunt your unicorn. Find a unicorn, ideally with a white or transparent background, with a size of 1024x1024px, and save it in .png format. (Feel free to borrow for your experiments. Don’t use it in a commercial project.)
3b) Next, transform your image to the correct sizes and give them the correct names, as stated in the Human Interface Guidelines. This involves Retina (2x) as well as standard files, so
icon_16x16.png
icon_16x16@2x.png
…

The reason for having separate 1x and 2x resources (and five steps instead of a single icon to scale up and down) is that this allow for highly detailed large images and simplified smaller icons. Instead of having to rely on the computer to scale, you can have, say, a single-hue 16×16 icon (where only the outline matters), and add a second hue and more definition to your larger version.

Personally, I’ve used the Free AppIcon Generator (free in the Appstore) to generate my icon sets; but I have to warn that it will generate an OSX.iconset from your image and ruthlessly overwrite any previous OSX.iconset in the same folder, so you want to give each one a sepate location.

Rename the folder (unicorn.iconset), right-click on it in the Finder and choose ‘quicklook’. This now gives you the chance to preview the icon in any size you like, or to seamlessly change the size and view the results. (If you’ve created it from a single large image, this is not overly interesting.)

You can add an imposter to your set: replace one unicorn with a kitten, and watch it scale from 1pt above the previous size to its nominal size, which tells us how the system handles scaling: 17-32pt uses icon_32x32.png, etc.

3c) Add your unicorn.iconset into your project and in both the document types and Exported UTI settings set the icon name for .unicorn files to unicorn. It should immediately show up in the settings; if the imageWell remains blank, check that you typed the iconset name correctly. (There is no autocomplete for this).

3d) Once you run your app, the Finder will know about the icon, but it is likely to still show the generic icon. File info may or may not show your icon as ‘preview’; open/save dialogs very probably will show your icon. All of this should be fixed after a restart of your computer, so _don’t panic_. (and especially don’t fall into a rabbit hole of ‘what if unicorn.iconset isn’t, as the documentation says, automatically compiled into a .icns file, and should I create one and swap them out and…’. No. Deep breath, it’ll be fine.)

(What makes a good icon is a whole topic in itself. My hastily thrown-together ones may be pretty at large sizes, but don’t work at Finder level (16x16px).

And more…

See the FileHandling master post – there are just *so many* topics. I haven’t touched on NSDocument-based apps, where some of these may work out differently.

Usage Example

As soon as your app moves beyond the utility (where you save only preferences, or maybe a private file in the apps ApplicationSupport folder) and into either opening or saving files, you need this stuff. On macOS, the Finder is the primary way for people to interact with your app, and if you fail to provide your own file icons for your files, the app will look unprofessional, unfinished.

Alternatives

None. It doesn’t matter how you create the files in question, interaction with the Finder is the same.

Extensions

There isn’t much to do here – you could write your own utility for creating .iconset folders if you don’t like the ones available, but the main focus for further attention is outside the coding realm and in the design of good, recognisable, fun icons: clear colours, easy to recognise even at small sizes, quite probable with a jump in level of detail betwen the small (16/32) and larger sizes.