Social

Recent Games

Contact
This form does not yet contain any fields.
    Monday
    Jul142014

    A Month of Kittens!

    A month ago yesterday we picked up a couple of kittens from the local shelter. I've tweeted a few pictures but I thought it was time to introduce them here on the blog. I also pulled my DSLR memory card and got around to looking through the pictures I took the day they came home.

    First off, here's Shenanigans:

    IMG_3336

    And here's Hijinks:

    IMG_3370

    If you like those images there's a bunch more on Flickr

    I'll call out them meeting up on that first day:

    IMG_0542

    and wrap up my photo love-fest with a picture of them from just a few days ago:

    IMG_0678

    It's so good to have cats around the house again!

    Tuesday
    Mar042014

    The Last (I Hope) Word on NSMutableCharacterSet

    Edited to add 2014-03-07: Filed a Radar for this bug. I can't link to that, but I also filed it on Open Radar.

    Edited to add: Reading the code snippets in here is difficult. I can't find a quick & easy way to make them have horizontal scrollbars if I use a pre tag around it. Rather that have them be truncated I removed the pre tags for now so they word wrap. I'll bug Squarespace about it later.

    This NSMutableCharacterSet bug! I keep poking at it, going "OK I guess that makes sense" and then a day later going "Wait. That can't be right." Quick review. The following line of code:

    NSMutableCharacterSet* fakeMutableSet = [NSCharacterSet decimalDigitCharacterSet];

    seems to work. But although the object you get will respond to NSMutableCharacterSet selectors it won't actually do anything. Specifically you can write this:

    [fakeMutableSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];

    formUnionWithCharacterSet returns a void so you can't tell if it worked or not, and in fact it will not work. Conceptually now I should have a set with the decimal digits and whitespace. What I have (as far as I can tell, you can't probe much into NSCharacterSets) is the exact same set I had before this call. If you want a mutable copy you have to call mutableCopy like so:

    NSMutableCharacterSet* mutableSet = [[NSCharacterSet decimalDigitCharacterSet] mutableCopy];

    So far so good. I understand why I need mutableCopy, but at first I didn't understand why A ) fakeMutableSet wasn't mutable and B ) given that it wasn't mutable calling formUnionWithCharacterSet didn't cause an unrecognized selector assert. Seems like either it should be mutable or it shouldn't respond to the selector.

    I finally got around to writing some test code and I've found enough that I'm convinced there is a real bug here and it's not at all what I suspected at first. I'll write this up in a radar after I finish this post. I've placed the source on GitHub if you want to follow along.

    The full test code does a bunch of introspection on a variety of NSCharacterSet and NSMutableCharacterSet objects. But here's the smoking gun part:

    NSCharacterSet* decimalSet = [NSCharacterSet decimalDigitCharacterSet]; NSMutableCharacterSet* fakeMutableSet = [NSCharacterSet decimalDigitCharacterSet]; NSMutableCharacterSet* mutableSet = [[NSCharacterSet decimalDigitCharacterSet] mutableCopy];

    All three of these end up pointing at an instance of an internal class called _NSCFCharacterSet. So yeah. The docs say NSMutableCharacterSet is derived from NSCharacterSet but not really in the sense I think of it. And guess what: _NSCFCharacterSet responds to the NSMutableCharacterSet methods! See:

    // So here's the catch right? _NSCFCHaracterSet can respond to formUnionWithCharacterSet but // DOESN'T WORK if the underlying data is not mutable. if ([[decimalSet class] instancesRespondToSelector:@selector(formUnionWithCharacterSet:)]) { NSLog(@"Attempting union with decimal set"); // Have to cast this call to compile, but note no cast is needed for fakeMutableSet // Also note this is NOT an unrecognizedSelector: we respond to this method [(id)decimalSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]; }

    Admittedly, yes I have cast decimalSet so the compiler does not complain but I expected the runtime to skip the call because the instances shouldn't respond to the selector. Somewhere up inside formUnionWithCharacterSet there is code that says "if I'm not mutable just sort of fail silently." It would have saved me a ton of time if that had at least logged a line that says "this call didn't work".

    So yeah, if NSMutableCharacterSet objects were really a different class than NSCharacterSet objects I would have had a compiler error when I wrote the offending line without the mutableCopy. If NSCharacterSet objects didn't have methods to responds to selectors from NSMutableCharacterSet then I would have had a runtime assert. The NSCharacterSet and NSMutableCharacterSet API's sort of falsely represent what the data does. I don't see anyway to catch this happening from my code. So if you're using NSMutableCharacterSet be careful.

    Does this extend to other NSMutable* classes? I don't know. These are the only ones I use where there are a lot of "return a pre-populated instances" method so I'd have more trouble making a real world example using NSMutableArray or NSMutableDictionary.

    Thursday
    Feb202014

    More iOS Utility Categories!

    The more I think about that whole NSMutableCharacterSet thing I'm not happy with my current understanding. I may dig into that more in the near future. But at the moment I'm on my tear of pulling some common/utility code that I use in both Road Trip and Combat Imp into a common repository and putting a Creative Commons license on it. Today's code is adjacent to the NSMutableCharacterSet issue, but not directly related so I can dodge the "Why didn't this crash before I fixed it?" question for now. Quick summary of the problem:

    I have many UITextFields where I want "numeric" values entered. I say "numeric" in quotes because it's quite a bit more complex than that. In Road Trip I need to accept strings like "$ 12,345.67". In Combat Imp I have some fields that are "just" numeric (round counter) and some that can take + and - signs (hit points, initiative modifier). All the fields need to take control characters or you can't backspace (and with an external keyboard you can hit things like Shift+Left Arrow to do selection.)

    Shameful confession time: my original algorithm for this built a big list of all the characters I would ever want and then inverted the set. The reason for this is that I could call string rangeOfCharacterFromSet and find the first character in a string that was from a set. If the range returned anything other than NSNotFound I knew an illegal character was in the string and I could chuck it. This always seemed super backwards to me. I finally got around to doing what I wanted to do: I wrote a category for NSString that returns YES if all of the characters in the string are members of a set. Now instead of writing:

    NSRange foundRange = [string rangeOfCharacterFromSet:nonlegalCharacters]];
    if (foundRange.location != NSNotFound) {
        NSLog(@"String is %@, location is %d", string, foundRange.location);
        return NO;
    } else {
        return YES;
    }
    

    Instead I build the character set of legal characters, cache that, and simply write:

    return [string isContainedInCharacterSet:initiativeAndHPLegalCharacterSet];
    

    (Both of these samples live inside textField:shouldChangeCharactersInRange:replacementString methods. Idea is when the user enters text I immediately validate the characters. If it's a 'g' and I only want numbers I reject it immediately. Doesn't even show up on screen.)

    Much like the last stupid little helper category I plunked this in its own GitHub. Feel free to grab it if you need. You may notice that there are obvious other tests I could write it this category. I may in the future but for now, this is the only one I need. I'm not pretending to write some sort of comprehensive set of tests here, I'm just providing little snippets of code that I've found useful enough to isolate out and share in projects.

    Wednesday
    Feb192014

    iOS Programming PSA

    If you've read and used my post about converting currency strings on iOS you'll want to check the update I just posted. I had a nasty bug in RoadTrip under iOS 7 where it wouldn't accept the correct characters in the various cost fields. It turned out that when I wrote the code originally there was a line that says something like:

    NSMutableCharacterSet* mutableSet = [NSCharacterSet decimalDigitCharacterSet];

    At the time, this would give you y'know a NSMutableCharacterSet. Under iOS 7 it gives you a NSCharacterSet and calling a mutate method on it will just fail. Since they all return void you can't tell why it didn't work. (Or indeed, even tell that it didn't work. The symptom in my specific code was that not all of the characters I thought were in the set showed up there. There was no error or print statement or crash or anything.) Instead you need to write something like:

    NSMutableCharacterSet* mutableSet = [[NSCharacterSet decimalDigitCharacterSet] mutableCopy];

    I think (but can't confirm 100%) that what happened was in the early days of ARC that line invoked a copy operation and thus created a mutable set. But as time wore on somebody enhanced that and now it just references a prebuilt set. And the rest of the problem is just the way Objective-C works. I understand why it happens, but it wasn't something I expected, especially coming back into this code after doing C++ for a year.

    Anyway, sorry if this bit anybody on the rear end!

    Thursday
    Feb132014

    UISplitViewController+QuickAccess

    OK, let's switch gears and not talk about cats for a while shall we? Although fair warning, this post will only be interesting to somebody who does iOS programming. Hey sometimes that happens. Last week I sold my car so California could get it dismantled. If you don't want programming articles ask me about that sometime, and maybe I'll write a post about that.


    OK, if you're still around you have some interest in code. Let's dive in. I have a few bits of code that are shared between the two iOS projects I'm working on currently. One is a dirt simple category that lets you quickly access controllers in an iPad UISplitViewController. In theory accessing the left controller is a single line of code, but it's a complicated line:

    - (UIViewController*)leftController {
        return [[self.viewControllers objectAtIndex:0] topViewController];
    }
    

    And this is really the way I think of split views: there's a left controller and a right controller. I understand why that is represented as an array of UINavigationControllers but the whole point is that UISplitViewController should be an abstraction. When I think "OK, we need to notify the left ViewController that I just opened the map view so it can update the UI elements" I just want the left controller. I don't want to start thinking about stacks of controllers contained in an array and figure out the proper string of messages to get the left controller.

    And I do that all over the place. I kept copying that damn string of messages around and every time the "Keep it DRY" birdie would hoot shamefully in my ear. So I finally got fed up enough to make a category to make UISplitViewControlller do what I want. Of course, this wasn't that DRY because I had two projects and they each had these source files but it was better.

    Today I finally got around to sorting out how to put the category in GitHub as its own project, make a local repository, and then pull those files into both projects. This is actually the small code trial run for doing the same thing with some code that works around an iOS bug involving NSMutableCharacterSet. More on that later!

    Anyway, if this category sounds useful to you I cleaned up the source, figured a modern Creative Commons license for it and put it on GitHub. Enjoy and let me know if you have any issues!