Macs have used many different formats for storing data like settings, but by far the most popular currently are property lists, usually marked with the filename extension
plist. Although not entirely peculiar to Apple, no other platform uses them as extensively as Apple’s operating systems.
Stored in either plain UTF-8 text or a more compact binary format, when you examine them they declare themselves to be XML conforming to Apple’s PLIST 1.0 definition. They’re structured into dictionaries <dict> and arrays <array>, within which are pairs of keys <key> and various values. The only comparable data files you’re likely to encounter in macOS are JSON, which aren’t in XML and usually start with a set of field names, followed by streams of text data. JSON is more usual for storing and transferring the contents of databases, rather than the key-value pairs of property lists.
Current property lists have their origin not in Classic Mac OS, but in NeXTSTEP, although those weren’t expressed in XML. Classic Mac OS used to do this sort of thing using resources, which are structured binary data saved in a type of extended attribute. Property lists changed most when they were incorporated into Mac OS X, and since then, apart from the introduction of a binary storage format, which should be transparent in use, haven’t changed radically.
Property lists are normally structured into a hierarchy, at the top of which is a dictionary or array. Dictionaries are key-value pairs like
which sets the value of AppleLocale to the text string en_GB. Values can themselves be arrays or dictionaries, and it’s common for property lists to run several layers deep in that way. There’s a limited range of value types defined in the PLIST 1.0 definition, so it’s usual for many numbers to be string values, which have to be converted back to their original datatype when the property list is accessed.
Preference files are normally managed by a macOS service
cfprefsd, officially named the Defaults Server, which makes their access simpler but creates a new set of problems. Because
cfprefsd retains property lists in memory and writes them to disk when it feels like it, trying to make manual changes to preference files is usually doomed to fail. When you think you’ve got them right,
cfprefsd will decide to save its version, overwriting all your changes and putting the file back to square one.
The basic tool provided to change managed property lists such as app preferences is therefore the
default command tool. For simple tasks, that works well, but when you’re trying to access a dictionary within a array, inside an array of other objects, it becomes increasingly impossible. As the man page for
defaults says: “Defaults can be structured in very complex ways, making it difficult for the user to enter them with this command.”
If you need to do anything more serious with a property list which is being managed by
cfprefsd, then you’re better off using a dedicated editor such as Thomas Tempelmann’s free Prefs Editor. This works with
cfprefsd to ensure that your changes aren’t mangled or overwritten by that service.
By and large, those property lists in various Library/Preferences folders are the ones managed by
cfprefsd. To inspect or edit one outside those, you can use any good text editor, such as BBEdit (my favourite), or a specialist XML editor if you prefer. There’s no shortage of material: examples of unmanaged property lists include:
- The Info.plist file required in every app and bundle; note that changing them will break any signature.
- LaunchAgents and LaunchDaemons files, which are responsible for configuring most services.
- A great many configuration files in the System.
- Software installation receipts, and the InstallHistory.
None of these, though, tell you what the individual key-value pairs ‘mean’, nor their possible values. Those come down to intelligent guessing, and a little observation and experiment. Whatever you do, keep a backup copy of the property list before you made any changes to it, so you can revert to that if you break anything important.