
Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
Most Mac programmers have used the command line, even if only briefly. Some use it to drive their source code control, some use it for Unix utilities like awk
and grep
, and some use it to build and run. There’s a handy technique using the command line that lets you exert control over your GUI apps.
A very brief command-line refresher: you type the command at the shell prompt and follow it with some arguments:
$ ls -l /
The command goes and does its thing, based on the arguments you gave it:
$ <b>ls -l /</b>
total 30445
drwxrwxr-x+ 50 root admin 1700 Feb 28 17:19 Applications
drwxrwxr-x 15 root admin 510 Nov 21 14:27 Developer
drwxr-xr-x+ 63 root wheel 2142 Jan 27 12:57 Library
drwxr-xr-x 4 markd admin 136 Nov 5 13:19 Local
drwxr-xr-x@ 2 root wheel 68 Aug 16 2011 Network
drwxr-xr-x+ 5 root wheel 170 Feb 27 13:12 System
drwxr-xr-x 6 root admin 204 Nov 5 15:42 Users
...
What many people don’t know is that you can run Mac applications from the command line. You dig into the Contents/MacOS
directory in the application bundle to find the executable. You can run TextEdit like this:
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit
Because you’re running the app just like any other command, you can pass command-line arguments to it. What kind of command-line arguments? You can pass some of the special toggles from TechNote 2124, OS X Debugging Magic. NSShowAllViews
causes all of the NSViews
to be outlined in different colors to show the containment hierarchy. You can run TextEdit in this mode:
$ /Applications/TextEdit.app/Contents/MacOS/TextEdit -NSShowAllViews YES
This causes TextEdit to look like an early 90’s X11 program:
You’re not limited to passing arguments to Apple’s applications. You can pass them to your own, as well. Command-line arguments of the form
-argumentName argumentValue
are automatically added to the NSUserDefaults
system. You can ask NSUserDefaults
for the value for the key (object, string, integer, etc) minus the minus sign. In this case, you would ask NSUserDefaults
for the value that’s located under the @"argumentName"
key.
Say your app has a cutting-edge hardware-based graphics renderer, and a fallback software-based one. Hardware is faster, but might have artifacts. Software is slower, but is always correct. You could let the user override the hardware renderer on the command line:
$ GroovyApp.app/Contents/MacOS/GroovyApp -useSoftwareRenderer 1
And query it in code:
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
BOOL softrend = [defs boolForKey: @"useSoftwareRenderer"];
If there was no command-line parameter this code would result in NO
value (zero). In the case of the program invocation above, softrend
would be YES
value (one). A digit was used at the command line, because -useSoftwareRenderer YES
causes NSUserDefaults
to treat the YES
as a string instead of a boolean.
So, how does this actually work? The NSUserDefaults
database is constructed with keys and values from a number of different “domains”:
The registration domain, which holds values set by -registerDefaults:
. These are transient and not stored on disk.
Language-specific settings
Global domain, with defaults for all applications
The bundle-ID domain. These are the values stored in ~/Library/Preferences/com.bignerdranch.groovyapp
The argument domain, with defaults parsed from the application’s arguments
Defaults are applied in that order, with items farther down in the list taking precedence over higher settings. That means you can override any defaults value from the command line.
When would you use command-line user default arguments? They’re great for adding hooks for debugging and testing. In the software rendering case above, you could have a method
- (BOOL) useSoftwareRendering;
The implementation of this method could use NSUserDefaults
to decide:
- (BOOL) useSoftwareRendering {
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
BOOL softrend = [defs boolForKey: @"useSoftwareRenderer"];
return softrend;
} // useSoftwareRendering
Now you’re developing new features and you want to test with software rendering, either to verify functionality or track down a bug. You can run the app like you saw before:
$ GroovyApp.app/Contents/MacOS/GroovyApp -useSoftwareRenderer 1
You can also make this change “permanent” by setting the user default:
$ defaults write com.bignerdranch.groovyapp useSoftwareRenderer -bool YES
Now your app will always use the software renderer until you alter this preference via the NSUserDefaults
API, with the defaults
command, or via the command line. This can be a good work-around for a user that has an unusual hardware configuration that’s breaking your app in the field.
If you’re lucky enough to have a testing crew, you can build them “knobs” that they can turn to improve their test cases. Say your app fetches new data from the net on a daily basis. If you drive the update check interval by NSUserDefaults
, your crew can exercise more test scenarios by decreasing the check time on the command line.
Our introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
The Combine framework in Swift is a powerful declarative API for the asynchronous processing of values over time. It takes full advantage of Swift...
Over the past several years the barrier to entry for adopting machine learning and computer vision-related features has dropped substantially. Still, many developers are...