More of a programming nerd than is strictly healthy. See also {nevyn.nu, thirdcog.eu, twitter}

Projects

Overooped

Rapid network protocol prototyping with TCAsyncHashProtocol

github:TCAsyncHashProtocol. I like constructing simple network protocols from plist/json-safe dicts, and transmit them over the wire as json. Easy to prototype with, easy to debug. Give TCAHP an AsyncSocket, and this is what it’ll do for you, plus support for request-response, and arbitrary NSData attachments.

It is an embarrassment and almost an insult that my example project is a massive 200 lines. I hope to be able to reduce the verbosity and boilerplate clutter of using TCAHP without making it heavy-weight. At the very least, I recommend that you use SPLowVerbosity.

An example of using TCAHP to send a request to update the server’s MOTD:

[_proto requestHash:$dict(
    @"command", @"setMessage", // the command is 'setMessage'
    @"contents", msg // Send 'msg' as the new message to set.
) response:^(NSDictionary *response) {
    // The server has replied.
    if([[response objectForKey:@"success"] boolValue])
        NSLog(@"Successfully updated message!");
    else
        NSLog(@"Couldn't set message, because %@", [response objectForKey:@"reason"]);
}];

And on the receiving side:

-(void)request:(TCAsyncHashProtocol*)proto setMessage:(NSDictionary*)hash responder:(TCAsyncHashProtocolResponseCallback)respond;
{
    NSString *newMessage = [hash objectForKey:@"contents"];
    if([newMessage rangeOfString:@"noob"].location != NSNotFound)
        respond($dict(
            @"success", (id)kCFBooleanFalse,
            @"reason", @"you should be kind!"
        ));
    else {
        _message = newMessage;
        respond($dict(
            @"success", (id)kCFBooleanTrue
        ));
    }
}

(Note the latest piece of magic that I added, where the selector of the delegate method is created based on the value of the key ‘command’ in the message. I quite like it.)

As you can see, the resulting protocol is very weakly typed. In theory, this means you will be making typos and not understanding why the hell your network seems broken; in reality, I’ve never had that problem.

“Software today is not engineering. Building the Empire State Building with three thousand people in a year is engineering. Programming today is more like the Egyptians piling blocks on each other and hoping it doesn’t fall over.”

— 

Paraphrasing Dr Alan Kay in his talk “Programming and Scaling”. I got the same sense of depression over the state of our industry when I read about Doug Engelbart’s amazing NLS system from ‘68 and the Hypertext Editing System in ‘67. Yes, we have millions and millions times faster computers today, but what we’re doing today is not news. They realized already in ‘68 that you want direct manipulation and collaborative computing.

Every day, I spend so much time building almost trivial functionality in thousands of lines of code, with brittle APIs that hook into other people’s brittle APIs, because that’s the code base we have, and every other code base seems to be roughly looks like that, too. I spend my weekends learning about C and C-like systems because that’s what I know; I don’t go around learning about compiler-compilers, I’m stuck in what my brain already “knows” that programming is like. I didn’t know twenty minutes ago that you could write a complete compositing 2d graphics environment with 26 compositing method in under 400 lines of code.

My very good friend Martin once told me how different it is to even think in Japanese and Chinese, how those thoughts can’t even be translated into English. Kay’s realization that the same holds true for programming is profound in a way I didn’t realize before.

Back in uni I unwittingly participated in an experiment. One of the teachers arranged two lab sessions with the exact same content, and put Java programmers in one and C++ programmers in the other. We were given some UML and were asked to implement it. The real task had actually been to see how fast we could build it (but were of course not told in beforehand that we were being timed); and while I was fastest in my group and it felt like the C++ came out pretty naturally, the result showed that it took me twice as long to write the code than it took on average for the Java coders.

Ever since then, I’ve been worried that even though I feel like I’m really fast with my tools, those very tools are holding me back, and I’m *really* just a tenth as fast as I could have been with another set of tools. I love ObjC, but it’s still C, it still got non-object types, there’s still manual memory management, everything is viciously verbose, and meta programming is still more limited than in some non-C languages.

UIKit: Hide the keyboard without a reference to the currently focused text field

Googling for answers to UIKit or iOS/iPhone programming problems today resembles googling for answers to JavaScript problems. There is so much horribly, horribly broken code out there, being promoted as the way to do things. Ranting aside, today’s problem is writing your own view controller container, and noticing that focused UI elements don’t dismiss their keyboard in response to viewWillDisappear: or similar. If this was MacOS, or AppStore approval didn’t exist, you’d just do [self.view.window.firstResponder resignFirstResponder]. You can’t do that though, firstResponder is private on window, don’t ask me why. cdyson37 on StackOverflow however, found the public API -[UIView(UITextField) endEditing:] hidden in a category in UITextField.h, that supposedly looks recursively through the receiver’s children for the first responder, and if found, resigns it. Perfect! A copy-pasteable code snippet for lazy googlers:

[self.view endEditing:YES]

Media keys hook in Mac OS X

There is no nice (or is it even official?) way of detecting and handling the media keys on the user’s keyboard. One can intercept events with type NSSystemDefined and subtype 8 in -[NSApplication sendEvents:], but this has major problem: any other applications that listen to the media keys will receive these events too. This means for example that if only Spotify is running and you want to pause your music, iTunes will start when you press play/pause. If you have VLC running in the background, it will also start playing.

Apple has solved this problem internally by having their media key using applications cooperate and resign media key controls to the application that was in the foreground most recently. However, there is no way for third party applications to join this cooperation.

I have implemented a workaround that does this using a CGEventTap in the Cocoa class SPMediaKeyTap. The advantage of using an event tap instead of just intercepting the events in -[NSApplication sendEvent:] is that you have the power to throw the event away. This way, we can decide to “own” the media keys and be the only app that listens to them.

This class is smart enough to resign the media key event tap whenever another application that we know will want to use the media keys becomes active, and keeps track of which media key using app was recently started.

If everyone uses this class, and everyone add each other’s bundle ID to that list of whitelisted bundle ID’s, we’ll get nice behavior from all apps. An even better solution would be if Apple provided a way of acquiring the media keys.

The value is limitless

(gdb) p (double)pow(10, 6)
$9 = inf

What. The. Fuck?! Do I need to relearn C AGAIN?!

xib + subversion + automerge = pain

Don’t let Subversion automerge your xib files. This error isn’t even on the freakin’ google:

ibtool: some object IDs were duplicated

You can work around this by 1) telling subversion the file can’t be merged by setting its mime type to application/octet-stream 2) requiring the file to be svn locked before you edit it for an exclusive lock. You can tell your subversion client to automatically give xib files these properties by adding a few lines to your ~/.subversion/config file.


## Under [miscellany]
enable-auto-props = yes

## under [auto-props]
*.nib = svn:mime-type=application/octet-stream;svn:needs-lock=*
*.xib = svn:mime-type=application/octet-stream;svn:needs-lock=*

Of course, your merged xib is still beyond saving, so just fetch the previous version and redo all your changes! (also, more on subversion locking and exclusive checkouts)