Mac Equivalent of the Windows Registry – ish

If you're a long time Windows power user and are recently switching over to the Mac, you may have wondered if there was something analogous to the Windows Registry .

However, if you've always been more of a Mac user, don't run away just yet as you may learn something.

In case you don't know what the Windows Registry is, here is a short definition from our good ol' friend Wikipedia.

Windows Registry is a hierarchical database that stores configuration settings and options on Microsoft Windows operating systems. It contains settings for low-level operating system components and for applications running on the platform that have opted to use the Registry.

You have probably already figured that since it's called the Windows Registry that there is likely not a Mac Registry that looks/operates the same way.

You are correct; however, where do all of the system and applications settings get stored if there is no registry?

If the Windows Registry is a place where system and application settings are stored, then the Mac equivalent of the Windows Registry would be a series of .plist files in several preferences folder on the Mac.

While researching how to automate bootstrapping my Mac development computer, I stumbled upon large number of .plist files in several folders that correlate to the installed applications and system settings. And boom BOOM boom just like that I discovered the holy grail of my Mac's system and application settings - kind of like the first time lift up the curtain and discover the Windows Registry.

What are .plist files?

A .plist file is a configuration file that contains a list of properties in either plain text or binary format. I'll go into more later about how to read and update values in these files later in the post.

For more info on plist files, check out the Wikipedia page...

Where can I find plist files?

I know of at least 2 locations that host the common system and application .plist files.

The first one is user specific and is in the following location:

~/Library/Preferences/

In my case (since my user name is jason)

/Users/jason/Library/Preferences/

The second location one is at the root of the system:

/Library/Preferences/

If you look into these folders you'll see a large number of plist files that follow reverse domain name convention (like com.apple.sample).

Here are some (not all) examples of system configuration plist files:

com.apple.ActivityMonitor.plist
com.apple.AddressBook.plist
com.apple.finder.plist
com.apple.preference.general.plist
com.apple.TextEdit.plist
com.apple.Safari.plist

In the same folder as the sample configuration files listed above are where you can find plist files that are associated to applications installed on the system.

com.apple.dt.Xcode.plist
com.google.Chrome.plist
org.herf.Flux.plist
com.skype.skype.plist

Now that we can find system and application configuration plist files, if you try to open them in a text editor you may notice that many of them are in a binary format which would be challenging to read and understand, let alone edit.

How do I read these files?

The Mac comes with a command line utility called defaults for reading and writing to these .plist files.

If you take an example from the above list of plist files, you can, at the command prompt type the following:

defaults read com.apple.fin<tab> (where <tab> is the tab key that allows tab completion of the rest of the property list format) and be sure to exclude the .plist of the end so:

defaults read com.apple.finder

will print out all of the properties to the console so you can inspect what's there.

You can pipe this output to grep and filter for a setting name when doing searches. Once you've found a property name you want to look at you can pass it into the defaults read command to get the value of that specific property.

Example reading a single property:

defaults read com.apple.finder AppleShowAllExtensions

How to change property list settings?

warning WARNING warning

Just like modifying the Windows Registry can mess up your system, you need to take care modifying system or application plist settings.

warning WARNING warning

Most of these settings can be changed by navigating to the application or system's respective preferences U.I. and just changing settings manually. However, the whole reason I ran down this path was to learn how to automate these setting changes.

When I first tried to change the settings I tried manually modifying the plist files with a GUI tool built into the Xcode developer tools.

However, and I have yet to understand the internals of this, after I made the changes to the plist file they would automatically get overwritten after a few seconds. So it seems that there is some official source of these values somewhere that for some reason overwrite the ones in these folder. I probably have that all wrong - but was an observation I had.

So if my understanding above is somewhat correct, how did I update the source?

Similar to reading property list values you can use the defaults command line tool to write changes back to the .plist files.

As an example, here's how I update Finder to show file extensions.

defaults write com.apple.finder AppleShowAllExtensions -boolean true

The configuration options are now endless.

In summary:

Using my new knowledge that app and system settings can be found in both /Library/Preferences and ~/Library/Preferences and I can use the command line tool defaults to read/write to understand and update settings.

I can now create a simple .sh script that allows me to pre-configure a new development machine with all of the settings I would like.

Now, each time I catch myself trying to use an application's preferences U.I. I stop myself and try to find that setting in a plist file and create a CLI command that I can save into my development setup script.

Happy Mac Settings Hacking!

Read More

Fail Fast With iOS Images

Problem: iOS app has unwieldy, unorganized and poorly named images

I've been working on a team that took over a good sized legacy iOS project where it's usage of images became a little unwieldy. Between the various app clones (targets), shared images, and images that aren't even used we'd like to reorganize, rename and just clean up the app in general.

But, one thing that makes me nervous is how easy it is to rename an image, forget or miss a magic-string that tries to load that image and now we've introduced a bug that may be difficult to diagnose or even discover that we introduced it.

Let's fail fast?

Failing fast in this context means, how can we, during development and testing time quickly fail when running the app to determine where an image attempting to be loaded does not.

Ideally we wouldn't even have these magic-strings to deal with. Using some tool to automatically generate a compile-time safe construct that we can use to load images. However until both A) I find the darn tool that I once-upon stumbled across that does this (please leave a comment to remind me if you find it before I do...) and B) we get sed tool integrated, I threw this little helper to quickly fail fast and help us find broken image references within our iOS applications.

How does it work?

It's a simple little Category that overrides the imageNamed: selector of UIImage and if the original cannot load an image (returns nil) then it will fail with a helpful assertion message.

This utility allowed us to quickly find images that were missing while doing our big clean sweep.

How to integrate?

It should be as simple as adding the .h & .m files to your project and their respective targets and you should be off to the races.

For DEBUG mode only...

If you look closely you'll notice #if DEBUG wraps the implementation so when we ship to the app store we don't end up causing a crash in production if a missing image sneaks by.

Happy Missing Image Bashing!

Read More

How to Diff Two Xcode Targets

If you've ever used different Xcode targets to manage different version or clones of a similar app and then had to debug why one target builds while another doesn't, finding a way to diff two targets was always challenging.

Sometimes it's because you forgot to check a box including a new class in multiple targets, or maybe you've integrated a new framework with targetA but forgot to include the framework reference in the Build Phases for targetB.

I'm actually hoping that I just haven't learned the obvious way to resolve these problems and you (dear reader) will leave a comment telling me how simple it is to do with the built in tools. Until then, here's something that I hope will help others that are trying to see what two Xcode targets have different between them.

How about a little CLI tool: diffXcodeTargets

diffXcodeTargets is a command line utility I threw together that allows you to visualize the differences between two Xcode project targets using a diff tool.

Install it with npm

npm install -g diffxcodetargets

How to use it?

You can first call it by passing in the path to your project file and no targets and it will print out what targets are available.

> diffXcodeTargets ./myProject.xcodeproj/project.pbxproj

Could not find TargetA ''. Possible targets are:
  - targetA
  - targetB

Now you know your available targets and you can call it with the two targets you want to diff:

diffXcodeTargets ./myProject.xcodeproj/project.pbxproj targetA targetB

How does it work?

If you're curious how this tool does it's job it is actually quite simple and would love to hear any feedback...

diffXcodeTargets uses the xcode npm module to read/parse xcode projects and then approvals to show a difftool with two different files.

What's missing?

I threw this together quickly to help diagnose some issues with a project I was working on. It does not yet support all of the various scenarios that may be needed when diffing two Xcode targets, but if you have any suggestions or ideas feel free to leave a github issue.

Happy Diffing!

Read More