Apples documentation of Regular Expressions With NSPredicate
has the full scoop, but basically you do
[NSPredicate predicateWithFormat:@"SELF MATCHES regex-here"];
. Unfortunately, you can only test if strings match a regex. You can not use an NSPredicate
-regex to extract parts of a string. Depending on what you need to do, this may or may not be enough to save the day.
September 20, 2008
Regex Matching and Filtering in Cocoa With NSPredicate
September 18, 2008
I Would Rather Have a Runtime Error Than a Compile Error
And the weird thing is, I realized early in my career that I would actually rather have a runtime error than a compile error. [(some laughs)] Because at that time… now this is way contrary to popular opinion. Everybody wants early error detection. Oh God, not a runtime error, right? But the debugger gives you this ability to start poking and prodding, especially in a more dynamic language, where you can start simulating things, you can back it up… You’ve got your time-machine debuggers like the OCaml one, that can actually save the states and back up.
You’ve got amazing tools at your disposal (in the debugger)… Whereas if the compiler gives you an error that says “expected expression angle-bracket”, you don’t have a “compiler-debugger” that you can shell into…
So, you know, in some sense, your runtime errors are actually kind of nicer.
— An excerpt from one of Steve Yegge’s (long!) talks.
I think there is a real nugget of truth in this. At runtime, you can examine your program’s state, but there is absolutely no way to do that at compile time. Without a debugger, you can’t just look at some nontrivial code and know what the value of x
is when there’s an error reading y
. (Adding "print x"
, recompiling, and trying again, would work of course, but that’s just using your compiler as an inefficient debugger!)
Similarly, Strong Typing vs. Strong Testing , essentially argues that some tests can only be made at runtime. (If you read any links on this page, read it, it’s much shorter and to the point).
September 17, 2008
The Price of Cool
For those who might doubt such a high value of cool, consider the self-winding Rolex, which sports 1/10th the accuracy of a Timex at 1000 times the price. With Rolex, the technology is grossly inferior, and still people will pay thousands to own it.
September 16, 2008
We’re In This Together
Leaving work late last Friday, I was impressed with the Bosch brand alarm-panel by the door. I botched entering the access-code, trying to arm the system, and the tiny LCD said,
Invalid Code
Let’s try again.
Security systems are designed to keep people out, have Spartan interfaces out of necessity, and consequently are often somewhat hostile to use. It’s a small thing, but that phrasing “let’s try again” made me smile, and that made a difference.
-description, Little-Known Hero of Debugging
Or: How to Make NSLog()
Useful With Your Objects
Say you have an archaically named NSArray
that you want to inspect — it’s easy to do, since NSLog(@"The bestiary is %@", bestiary);
prints out the array’s contents
2008-09-16 19:46:06.445 Tester[2678:10b] The bestiary is (
Cheetah,
Pumpa,
Jaguar,
Panther,
Tiger,
Leopard
)
But if you try to NSLog
your own object, you get pretty useless output, like
myObject = <MyObject: 0x53f330>
Fortunately, it’s easy to fix! Just implement the method -(NSString*) description;
and whatever it returns will be printed by NSLog
and GDB (po object
, will print object in GDB and the Xcode debugging console).
Here’s an (unfortunately complex) example,
- (NSString*) description;
{
return [NSString stringWithFormat:@"<%@ %p> = {\n\tquestion=%@,\n\tanswer=%@,\n\tsource=%@\n}", [self className], self, self.question, self.answer, self.source];
}
output:
myObject = <MyObject 0x53eed0> = {
question=What is the Best Thing Ever Of All Times, Ever?,
answer=The Internet!,
source=http://www.cabel.name/2008/01/2007-cabel-yay-awards.html
}
Useful Formatters and such
These macros have made my debugging-life easer.
%p
tells NSLog
to print the address of a pointer.
-className
returns gives the name of a class as an NSString
.
Don’t manually print out a Cocoa struct
, ever, there are already NSStringTo*
functions to do that for you, like NSStringFromPoint()
.
NSStringFromSelector()
works as advertized (and paired with NSSelectorFromString()
is very useful in general).
%lld
tells NSLog
to print a long long
(64-bit integer). See also, printf
reference.
%Lf
tells NSLog
to print a long double
. See also, printf
reference.
Best Practices
Whenever you make a new object, I strongly recommended immediately implementing a description
method, and religiously keeping it up to date (it’s not hard, honest!). This won’t fix bugs, but it will make finding some of them much easier.
September 14, 2008
Fast Enumeration Really Is Faster
Your code will also run faster because the internal implementation reduces message send overhead and increases pipelining potential.
I’ve written before about the advantages of a better enumeration paradigm, clearer code that’s faster to write, shorter, and with fewer bugs.
If you program in Cocoa, you should adopt fast enumeration post-haste.
September 11, 2008
Detecting if Headphones are Plugged In
I found many posts on mailing lists asking the question of how to detect if something is plugged into the headphones jack, but no complete answer. So here’s how I do it.
Docs & Tools
Use the CoreAudio.framework, specifically CoreAudio/CoreAudio.h
Unfortunately it’s a bit confusing sometimes, but the documentation is still very complete (if complex).
HALLab (/Developer/Examples/CoreAudio/HAL/HALLab/
if you have the developer tools installed) is the most complex bit of relevant CoreAudio sample code, and when built it’s a useful utility for poking-around with to boot.
How To Do It
Whenever something is plugged into the headphones jack, CoreAudio changes the data source for the output device, from internal speakers to headphones. Use AudioDeviceGetProperty(outputDeviceID, 0, 0, kAudioDevicePropertyDataSource, &size, &dataSource);
to examine the 32-bit ID of the data source, which is best thought of as a 4 character code. If dataSource
is 'ispk'
, sound is played through internal speakers, if it is 'hdpn'
, sound is playing through the headphones jack. I’m not sure what happens if you have speakers plugged in that use a different output source, like USB, FireWire, or optical out.
A word of caution, do not use the promising-looking AudioDevice Property kAudioDevicePropertyJackIsConnected
it does not work on all systems (specifically it didn’t work in 10.4, and I have not tested it under Leopard).
Change Notifications
If you want to be notified when something is plugged/unplugged in the headphones jack, listen for a kAudioDevicePropertyDataSource
change to the output audio device. Here is the code I use to test if a computer is using it’s internal speakers:
Sample Code:
//Returns YES if the default sound output device
//is using external speakers to play sound.
- (BOOL) usingInternalSpeakers
{
AudioDeviceID deviceID;
UInt32 size = sizeof(deviceID);
OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &size, &deviceID);
NSCAssert((err == noErr), @"AudioHardwareGetProperty failed to get the kAudioHardwarePropertyDefaultSystemOutputDevice property");
//To be notified when something is plugged/unplugged into the headphones jack
//listen for a kAudioDevicePropertyDataSource or kAudioDevicePropertyDataSources notification on deviceID
//Check if headphones are plugged in right now:
UInt32 dataSource;
size = sizeof(dataSource);
err = AudioDeviceGetProperty(deviceID, 0, 0, kAudioDevicePropertyDataSource, &size, &dataSource);
NSCAssert((err == noErr), @"AudioDeviceGetProperty failed to get the kAudioDevicePropertyDataSource property");
//'ispk' => internal speakers
//'hdpn' => headphones
return dataSource == 'ispk';
}
September 6, 2008
Complexity Is the Enemy
Complexity is the worst enemy of security; as systems become more complex, they get less secure.
The Term “Sprint” is Very Wrong for Software Projects
My employer is big on Scrum-flavored Agile Software Development. This is not a critique of “Agile” practices (if you want one Steve Yegge won’t let you down). I just don’t have enough experience organizing software projects to judge if this whole “Agile” thing is working well or not. But I do think the choice of the word “Sprint” to denote a unit of work is harmful.
A sprint is unsustainable. Fully recovering from a true-sprint takes a long time. To be ready to sprint again, you must rest for far longer then the sprint lasted. And you’re pretty useless (at least running-wise) while you rest. These are simple things that we learned as kids on the playground. This is what “sprint” means to people.
Calling repeated multi-week units of sustainable and quality work a “sprint” makes no sense whatsoever. Worse, it subtly encourages over-exertion and behaviors that are detrimental to a project.
It might be argued that in the context of Scrummy-Agileness, “Sprint” is a technical term, divorced from the common parlance. Whatever. Words don’t change meaning overnight, and they are almost never their own antonyms. Word-choice is known to influence people.
Sure, word-choice alone isn’t enough to derail a project, or sink a methodology. That’s why this isn’t a criticism of “Scrum”, which will ultimately stand or fall for other reasons. But there are plenty of much better terms to describe a chunk of work, that will help long-term productivity. Wouldn’t you rather work for a company that evaluated how effective a “Play” was?
September 5, 2008
The ‘Apple Stands on 3rd Party Shoulders’ Theory
Do you know what the real difference is between a Mac and a PC?
It’s not just the OS. A platform always stands or falls on third-party development. The difference is that Mac software tends to be well designed, and Windows software tends to suck.
—Mike Lee, being “an elitist Mac-fan wanker”. Some interesting comments so far.