by Alex Rozanski

Parsing command line arguments with NSUserDefaults

Jan 22nd 2010Published in Cocoa, Development

The NSUserDefaults class provides Cocoa applications access to the underlying Mac OS X defaults system, and can be used to store and persist user preferences.

Whilst providing an interface to the defaults system, the NSUserDefaults class can also be used to access command line arguments that were passed when the executable was launched, which have already been parsed and are accessed in the same way that other defaults are. This can be a great convenience when dealing with applications that accept command line arguments, such as command line tools.

Defaults domains

Defaults are organised into domains, each of which are assigned a name and are used to separate defaults intended for different purposes. Domains can either be persistent or volatile – persistent domains persist their defaults to disk and remain if the application is terminated and relaunched. Volatile domains only exist from the point at which they are created to when the user defaults object is deallocated.

The standard defaults domains – listed in order of precedence – are:

  1. NSArgumentDomain – this is a volatile domain that contains any command line arguments that were passed when the application was executed.
  2. The application-specific domain – the persistent domain that is based on the application’s bundle identifier. At current the defaults for this domain are stored in a .plist file at ~Library/Preferences/<ApplicationIdentifier>.plist
  3. NSGlobalDomain – a global defaults domain that is intended for use by all applications running under the user that the domain applies to.
  4. Languages Domain – these are volatile domains used for language-specific defaults based on languages set in the NSGlobalDomain under the AppleLanguages key.
  5. NSRegistrationDomain – a volatile domain that allows “factory settings” to be set by the application. This provides a fallback so that the application can always rely on NSUserDefaults to return a value for certain defaults, even if they have not yet been overridden and saved in the defaults database in the application-specific or global domain (this is useful on first launch, for example).

The order of precedence is important – when you request a value for a given key, the defaults domains are searched in this order. The first key that is found that matches the requested key is used. This means that, for example, if a key is present in the application-specific domain and also in the global domain, the value set in the application-specific domain will always be found first and used.

Parsing command line arguments with the NSArgumentDomain

The NSArgumentDomain is a particularly useful domain for applications that use command line arguments. The domain is volatile, and when created the defaults dictionary is populated with any command line arguments that were passed when the application was executed.

Command line arguments that can be parsed and used by the NSArgumentDomain must take the format:

-name value

The argument is stored as a default with key of name and value of value.

At this point accessing values passed in on the command line is the same process for accessing any other defaults. For example running an application as such:

MyApplication -aString "Hello, World" -anInteger 10

Allows the command line arguments to be retrieved as such:

NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];

NSString *aString = [standardDefaults stringForKey:@"aString"];
NSInteger anInteger = [standardDefaults integerForKey:@"anInteger"];

NSLog (@"aString argument: %@\nanInteger argument: %d", aString, anInteger);

With the following output:

aString argument: Hello, World
anInteger argument: 10

The importance of domain precedence

The NSArgumentDomain has the highest precedence when a key is searched for in the user defaults, and as such defaults set in different domains with the same keys as the command line arguments will be temporarily overridden. For example, if the application is invoked from the command line as follows:

MyApplication -myKey "Foo"

but myKey also exists in the application-specific defaults domain with a value of “Bar”, then calling:

[[NSUserDefaults standardUserDefaults] valueForKey:@"myKey"];

will return “Foo”. The default set in the application-specific domain is not overwritten, but the default in the NSArgumentDomain is encountered first as it has the highest precedence.

Comments — 2

  1. Alexis Gallagher

    Feb 7, 2014

    This is wonderful to learn about. Thanks for posting this. I cannot believe I’ve spent so long hunting for libraries to ease command-line argument parsing for Cocoa apps, without ever discovering this.

    If only there were some way to automatically generate a usage string…

  2. Federico

    Apr 11, 2014

    Hi, thank you for this post!
    I have a question, how manage the arguments without a value, for example a classic -h (alias -help) instead use an ugly “-h YES”

Add comment

Please enter your name and comment