Measure twice, refactor once

Just a quick year end post for my loyal readers…

When you are looking to make performance improvements on your iOS app, no matter how well you think you know the code, fire up Instruments and run your code on a real device. Before the holiday break, I was not going to do this because I was certain where the code was slowing down, but on a lark I decided to profile it and needless to say it was a real eye opener. I saved myself a bundle of time by not chasing down phantom slow downs, made the code run super super fast, and got the girl in the end. (OK, maybe not that last one.)

Happy and prosperous New Year to one and all.

Overriding a TargetType Style without a Key in WPF

I have been doing a lot of work in WPF lately, and it is a different animal.

The default styles of a button did not look right for my application, so I came up with the following XAML that styles up all of the button objects in my application:

<Style TargetType="{x:Type Button}">
    <Setter Property="SnapsToDevicePixels" Value="true"/>
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="Background" Value="CornflowerBlue" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="Border" CornerRadius="0" BorderThickness="0" 
                            Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding Background}">
                    <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="Border" Property="Background" Value="#4667A5" />
                    </Trigger>
                    <Trigger Property="IsPressed" Value="true">
                        <Setter TargetName="Border" Property="Background" Value="#3C588C" />
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="Border" Property="Background" Value="LightGray" />
                        <Setter TargetName="Border" Property="BorderBrush" Value="#AAAAAA" />
                        <Setter Property="Foreground" Value="DarkGray"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="true">
                        <Setter Property="Foreground" Value="White"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

As you can see, I am using TemplateBinding to bind to the desired background color.

However, in one of my user controls, I want to be able to change the background color of the button in certain situations. Initially, I just created a copy of the above XAML, gave it a Key, and then used that key name to style up the Buttons that I wanted to.

As always, there is a better way. I found that there was a way to use a BasedOn in my new style to pull in the style from the global resources and just change what I needed, here is what it looks like:

<Style x:Key="SpecialButton" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="Width" Value="20" />
    <Setter Property="Visibility" Value="Collapsed" />
    <Setter Property="Content" Value=">" />
    <Setter Property="IsTabStop" Value="False" />
    <Setter Property="Background" Value="LightGray" />
</Style>

BTW, Happy Birthday to Eugene Levy, by far one of the funniest actors out there.

A prediction by the USPS???

When I was looking through my father’s collection of U.S. Postal Service First Day Covers, I found this gem. You would think that our postal service would have been more vocal about this in the past 38 years or so.

BTW, Happy Birthday to Charlie Batch, engineer of an improbable win for the Pittsburgh Steelers over the Baltimore Ravens this past weekend. It was nice to see an old guy like me doing something awesome.

The technical term is “Leap Month”

So I am guessing that Google needs some help in their development and/or QA departments. Or else Google knows something that the rest of us don’t know…

I saw this little nugget tweeted about this morning and had to try it for myself. Sure enough, my Galaxy Nexus 7 with Jelly Bean 4.2 is missing the entire month of December. (To reproduce, go into the People app, edit a contact, tap ‘Add another field’, select ‘Events’, and notice that December is not in the month scrolly.)

In an unrelated story, I predict that Android 4.2.1 will be coming out very soon.

BTW, Happy 50th Birthday to Kirk Hammett, lead guitarist for Metallica.

Hello NSScanner

In an attempt to broaden my iOS development horizons, I thought I would take a look at some of those iOS classes and components that you may not know too much about or have used in the past, but probably should due to their elegance or functionality.

Today’s example is NSScanner (reference and programming guide). This handy class has one main purpose, to scan through a source string into either strings or other data types, such as integers and floats.

Converting a NSString to an integer is fairly trivial, as you can just do something like [myString intValue]. However, the NSScanner class maintains a pointer as the source string is scanned, so if you need to loop through a string and scan multiple values in from one string, NSScanner is your class. One other interesting thing that NSScanner can do is to take in a string of hexadecimal digits and convert them as well.

In the simplest case, here is how you would convert a string to an integer:

NSString *theString = @"42";
unsigned int theValue;
[[NSScanner scannerWithString:theString] scanHexInt:&theValue];

All of the scan methods return a BOOL that lets you know if the scan was successful or not, so be sure to not do what I am doing above and check the return value to make sure there was not an error.

Here is how you would process a hexadecimal string and examine each byte in the string:

int theLength = [hexString length];
for (int i = 0; i < theLength; i += 2)
{
    NSRange theRange = NSMakeRange(i, 2);
    NSString *hexDigits = [hexString substringWithRange:theRange];
    unsigned int theValue;
    [[NSScanner scannerWithString:hexDigits] scanHexInt:&theValue];
    NSLog(@"Byte number %d is %d\n", (i / 2), theValue);
}

And a final example, let’s say you had the text of an HTML page and you wanted to pull out all of the links in the page (denoted by an A tag with an HREF= entry). Here is some code that would do that:

NSScanner *scanner = [NSScanner scannerWithString:theHTMLString];
NSString *foundString = nil;
[scanner scanUpToString:@"a href=" intoString:nil];
while (![scanner isAtEnd])
{
    [scanner scanUpToString:@"\"" intoString:nil];
    scanner.scanLocation++;
    [scanner scanUpToString:@"\"" intoString:&foundString];
    [scanner scanUpToString:@"a href=" intoString:nil];
    NSLog(@"Link found: %@", foundString);
}

If you would like to download the NSScannerTest project that I put together to demonstrate these features in a running app, here is the download link, make sure to be using the latest version of Xcode and iOS SDK:

NSScannerTest source code

(Bonus mini tutorial: If you download and look at the source code, you will get a little sampling of NSRegularExpression and NSTextCheckingResult, two Foundation classes that probably deserve a tutorial posting of their own in the future.)

I have a couple of ideas on what I am going to cover next, but if you have any suggestions, please use the comments. Thanks and I’ll see you next time.

DBNull string field handling

Let’s say for the sake of argument that you are using a SQL Server Compact database in your C# .NET application, and your User table has nvarchar fields that are nullable, and your User class doesn’t care if those fields are null, it just wants empty strings instead.

Sadly to say, you are eventually going to end up with nulls in those fields, and as a result, if you use a SqlCeDataReader to step through a record set, this kind of stuff will (at some point) give you a runtime error:

myUser.UserName = (string)dataReader["UserName"]);

So I started looking for the best way to handle this problem. What I didn’t want to do was this for every single string field assignment:

myUser.UserName = (System.DBNull.Value == dataReader["UserName"] ? "" : dataReader["UserName"]);

This seems a bit wasteful to me, as the data reader is accessed twice. Sure, I could have encapsulated this into a function to pretty up the code a bit, but that would just be hiding the ugliness. Then, it occurred to me to try the Convert class to see what would happen, and it turns out that this code knows how to convert a DBNull to an empty string:

myUser.UserName = Convert.ToString(dataReader["UserName"]);

The Convert class may in fact do the same thing as I have shown above, but I would hope that Microsoft would make their built in function better than something that I would just hack together.

BTW, I hope everyone out there has voted, this is an important election. (Finally, tomorrow I can watch TV or get the mail without being bombarded by increasingly stupider campaign and “issue” advertisements.)

Bonnie, please put me through to Commissioner Gordon…

I think I may have determined where the Riddler is hiding out…

Or at least, where he puts the riddles he doesn’t use.

Oh, and I don’t know who put this together, but me likey…

BTW, it has been one year since the untimely passing of Dennis Ritchie, a true giant of the software world. All developers owe him a debt of gratitude.

iOS 6 Calendar and Address Book issues

I’m sure that it was noted somewhere in the docs or change log, but apparently they changed the way that you access the Calendar and Address Book data for iOS 6. Previously, you could just create an event store or address book object and fire away, but now there is an extra step involved.

Now, you have to request access, and then in the callback that fires when access is granted by the user, perform the actions that you need to do with the object.

So here is what the code to access the Calendar looks like:

EKEventStore *eventStore = [[EKEventStore alloc] init];
if ([eventStore respondsToSelector:@selector(requestAccessToEntityType:completion:)])
{
    [eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (error)
            {
                // display error message here
            }
            else if (!granted)
            {
                // display access denied error message here
            }
            else
            {
                // access granted
                // do the important stuff here
            }
        });
    }];
}
else
{
    // do the important stuff here
}
 
[eventStore release];

And here is what the code looks like to access the Address Book data:

if ([self isABAddressBookCreateWithOptionsAvailable])
{
    CFErrorRef error = nil;
    addressBook = ABAddressBookCreateWithOptions(NULL, &amp;error);
    ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (error)
            {
                // display error message here
            }
            else if (!granted)
            {
                // display access denied error message here
            }
            else
            {
                // access granted
                // do the important stuff here
            }
        });
    });
}
else
{
    addressBook = ABAddressBookCreate();
    // do the important stuff here
}

And in the above code, here is the method that tests for the existence of the ABAddressBookCreateWithOptions function:

- (BOOL)isABAddressBookCreateWithOptionsAvailable
{
    return &ABAddressBookCreateWithOptions != NULL;
}

And also, I am not sure if this is an iOS 6 thing or not, and ultimately I am not sure if it will help in the long run, but in my own testing of generating PDFs on an iOS 6 device, I found that using the Core Foundation function CFAttributedStringSetAttribute was causing intermittent crashes. So I switched to using the function CFAttributedStringSetAttributes instead, and it seemed to work much better. Here is a code sample of what that looks like:

CFMutableDictionaryRef fontDict = CFDictionaryCreateMutable(NULL, 1, NULL, NULL);
CFDictionaryAddValue(fontDict, kCTFontAttributeName, fontRef);
CFAttributedStringSetAttributes(currentText2, CFRangeMake(0, CFAttributedStringGetLength(currentText2)), fontDict, false);
CFRelease(fontDict);

BTW, happy birthday to Chevy Chase, one of the best comic actors ever.

Reactive Cocoa (CIDUG meeting, September 25, 2012)

Josh Abernathy of GitHub gave a presentation on the Reactive Cocoa framework last night at the CIDUG meeting. His way of describing the framework was a way to encapsulate and perform operations on a sequence of values over time. His UI demo using the framework was interesting, it was a bit hard to wrap the brain around in a quick demo setting, I would have to look at it again to try to understand and digest how it works and is beneficial over standard ways of doing UI operations.

BTW, today is the anniversary of the passing of Shawn Lane, who was an immensely talented guitar player. Any time you are feeling low, keep in mind that there are people who have gone through worse.

The app delegate’s UIWindow is finicky

I learned the hard way that there is a right way to do things in your didFinishLaunchingWithOptions with regards to self.window, and then there is the way that Apple used to have apps work that does not work any longer.

In case you haven’t heard, screen rotation in iOS 6 is much different from the previous versions of iOS. As a result, I was banging my head against the wall trying to figure out the magic incantation to get my rotation working again, and as it turned out, it had to do with this line of code in my app delegate:

[self.window addSubview:navigationController.view];

I was building my UINavigationController in the code and assigning it to the window as shown above. On the advice of an enterprising Stack Overflow user, I changed the line of code to this:

[self.window setRootViewController:navigationController];

And now the rotation events are starting to once again fire in my app. Yay.

For some additional information on how iOS6 handles rotation differently, please visit this blog post, which is where I found part of the information that I needed to get rotation working again in my app:

iOS 6 SupportedOrientations with UINavigationController – Shabbir’s Code Snippets

BTW, Happy Anniversary to Devil’s Tower, which was declared to be the first National Monument in the U.S. on this date in 1906. I now have a burning desire to watch Close Encounters for about the 100th time.