Swift Regex Deep Dive
iOS MacOur introductory guide to Swift Regex. Learn regular expressions in Swift including RegexBuilder examples and strongly-typed captures.
I’m a fan of Caveman Debugging, where you use print statements to trace program flow and display specific program information. I was kind of surprised when reading Coders at Work how many industry luminaries do the same thing. It’s just another tool in the debugging arsenal, along with unit tests, debuggers, Instruments, and the plethora of other software investigation toys.
When Caveman Debugging, I usually just use NSLog
. It’s handy and easy to type. But sometimes I get annoyed by its verbosity. Like when I print out this array:
NSArray *array = [NSArray arrayWithObjects: @"Greeble", @"Bork", @"Fnord", nil];
NSLog (@"The array is %@", array);
I get this in the Xcode debugger pane, or out to a terminal window:
2012-06-24 21:05:19.731 log[45714:303] The array is (
Greeble,
Bork,
Fnord
)
Knowing the year, time, program, pid, and thread ID definitely have their uses, especially when I have log statements in a book – I can tell exactly how many years ago it was I ran that particular piece of code.
But there are times where all that stuff isn’t germane to the problem I’m tracking down, especially if I’m running a program in a narrowish terminal. That extra info pushes the useful content off to the right, sometimes wrapping the line around. Also, I can’t just skim down the left-side of the window. Most of array being logged is flush-left, but the first line starts halfway across the screen.
Additionally, NSLog
sends its text to the system console. Sometimes I might be logging something that shouldn’t be enshrined in the system log, such as passwords or security tokens, or the contents of my Patsy Cline / Rammstein playlist.
So I can’t use NSLog
if I want less chatty output. What options do I have now? The next level down in the technology stack is the C standard library, which has the printf
family of functions. Flexible, powerful, and well-known, I can pretty much use the exact same log strings with printf that I can with NSLog
. One problem, though. The standard library is below Cocoa and Objective-C, so it has no idea how to handle the %@
format specifier, which just sends description
to the corresponding object in the argument list. Not being able to use %@
is a serious limitation when caveman debugging Cocoa [Touch] applications.
In that case, I dust off my QuietLog function and use it (you can find it at this gist)
void QuietLog (NSString *format, ...) {
va_list argList;
va_start (argList, format);
NSString *message = [[NSString alloc] initWithFormat: format
arguments: argList];
va_end (argList);
fprintf (stderr, "%sn", [message UTF8String]);
} // QuietLog
So, how does this work? It’s a pretty standard varargs function. See the stdarg manpage if you’re curious about the full details. This function just turns around and calls an NSString
method that does the heavy lifting for me.
Here’s the function line-by-line:
void QuietLog (NSString *format, ...) {
This declares a function named QuietLog
that returns nothing. It takes an NSString
for the format string. The three dots say that the function can be passed an arbitrary number of arguments. What happens to those arguments is entirely up to the function. In this case, the consumption of arguments is driven by the format string. You’ve used differing varargs semantics before, such as terminating the list of objects with nil with NSArray
’s arrayWithObjects:
, and passing pairs of objects for NSDictionary
’s dictionaryWithObjectsAndKeys:
, and.
Varargs functions have to take at least one parameter. That parameter is how the argument processing machinery knows where to start looking for the extra arguments, which you pass to va_start
:
va_list argList;
va_start (argList, format);
argList
is a local variable of type va_list
. va_list
is an opaque type which acts like a pointer into the call stack. Calling va_start
, in essence, makes va_list
point to the next function argument after format. If you were processing the arguments yourself, you’d call va_arg
with an expected type, and you’d get the value back from the next argument.
Luckily, QuietLog
doesn’t have to do that much work. NSString
has a method, initWithFormat:arguments:
that will take the format string and one of these variable list pointers and make a string out of it.
NSString *message = [[NSString alloc] initWithFormat: format
arguments: argList];
If you’re not using ARC, you’ll want to autorelease this.
initWithFormat:arguments:
looks at the format string (which QuietLog
just turns around and passes on unmodified) and processes the argument list, including the hyper-useful %@
format specifier. The end result is an NSString
with the format string with its format specifiers replaced with the appropriate data values.
Any function or method that takes a va_list
can be used like this, as the workhorse for some higher-level purpose. Cocoa has a couple of them, such as one for raising exceptions, and methods to create new strings and predicates.
va_end (argList);
Clean up any state that might be used to point into the call stack.
So now there’s an NSString
with the contents we want to log. Time to print it out!
fprintf (stderr, "%sn", [message UTF8String]);
UTF8String
converts the string (if necessary) into a zero-terminated stream of bytes, a form suitable for passing down into the C standard library. This code prints out the string, along with a newline, to the standard-error stream.
Now the logging is much quieter:
NSArray *array = [NSArray arrayWithObjects: @"Greeble", @"Bork", @"Fnord", nil];
QuietLog (@"The array is %@", array);
which prints out
The array is (
Greeble,
Bork,
Fnord
)
(and, of course, I have to plug Advanced Mac OS X Programming, the Big Nerd Ranch Guide , which covers varargs processing)
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...
SwiftUI has changed a great many things about how developers create applications for iOS, and not just in the way we lay out our...