Frame geometry macros to improve your UIKit code

Frame geometryI find myself doing more and more dynamic UI layout in iOS apps these days. When elements of a UI need to resize to fit their contents, or move to accommodate other elements, the layout code can get complex and verbose. We’ve developed a set of Objective-C UIKit macros that help make this code more readable, self-documenting, and easy to change.

When a view is offset from another view, you might write something like this:

someView.frame = CGRectMake(someOtherView.frame.origin.x + someOtherView.frame.size.width + padding...

These macros help make that code more concise and scannable:

someView.frame = CGRectMake(RIGHT(someOtherView) + padding...

You can download the macros from our TBMacros Github repo. First let’s take a look at an example Continue reading

Objective-C Singleton Pattern Updated For Testability

SingletonAt Two Bit Labs we do a fair amount of unit testing. In places where we use singletons we use a variation on the the Objective-C dispatch_once pattern of thread safe singleton creation. This variation supports resetting the singleton or replacing it with a mock object.

That way in our unit tests we can do the following:
Continue reading

Objective-C Blocks Cheat Sheet

iOS Blocks Objective-CBlocks are an incredibly powerful addition to Objective-C, introduced in iOS 4. However, their syntax can be maddeningly difficult to remember. Matt Gallagher has an excellent post that breaks down the syntax to help you understand it. If you haven’t read this article, go do it now.

Even after working with blocks for a while, I still get tripped up. So I created the cheat sheet below, which I frequently refer to when declaring blocks. Continue reading

Block initialization for testability and reuse

BlocksSince Apple introduced block support in iOS 4, more and more APIs are moving from delegation to block callbacks. While block callbacks can be declared inline, in most cases you should initialize your block callback in a method that returns the block. This keeps the code that calls an external API succinct, allows you to reuse the block in different contexts, and makes it easier to unit test the code in the block.

Let’s see what this looks like in practice.
Continue reading

Empty or incorrect URL with webViewDidStartLoad

If you’re using a UIWebView in your iPhone or iPad app and you want to execute some code when a page starts loading you’ll likely turn to the webViewDidStartLoad: method in UIWebViewDelegate. However, you may have surprisingly unpredictable results. For example, the following code won’t work as expected:

- (void)webViewDidStartLoad:(UIWebView *)webView {
    if ([webView.request.URL hasPrefix:@"http://mywebsite.com"]) {
        // Show buttons specific to my site
    }
}

The issues you’ll run into are:
Continue reading

Some great UIColor resources

I’ve recently come across some nice resources for working with UIColors.

Developer Color Picker

Developer Color Picker screenshotDeveloper Color Picker is a color picker built for, you guessed it, Objective-C developers. Just install it in ~/Library/ColorPickers and it will appear in any application when you pull up the color picker. You can switch between RGB and HSB sliders (or just find the color in one of your other pickers), then click the Copy button to copy a snippet for that color to your clipboard. Depending what format you choose, the snippet can be one of several Objective-C formats:

// NSColor RGB calibrated
[NSColor colorWithCalibratedRed:0.405 green:0.344 blue:0.786 alpha:1.000]
// NSColor RGB device calibrated
[NSColor colorWithDeviceRed:0.405 green:0.344 blue:0.786 alpha:1.000]
// NSColor HSB calibrated

[NSColor colorWithCalibratedHue:0.690 saturation:0.563 brightness:0.786 alpha:1.000]
// NSColor HSB calibrated
[NSColor colorWithDeviceHue:0.690 saturation:0.563 brightness:0.786 alpha:1.000]
// UIColor RGB
[UIColor colorWithRed:0.405 green:0.344 blue:0.786 alpha:1.000]
// UIColor HSB
[UIColor colorWithHue:0.690 saturation:0.563 brightness:0.786 alpha:1.000]
// CGColor
CGColorCreateGenericRGB(0.405, 0.344, 0.786, 1.000)

Or, for CSS:

/* Hex */
#6758c8
/* RGB */
rgb(103, 88, 200)
/* HSL */

hsl(248, 51%, 56%)

Picker.app

Picker screenshotPicker is an app that puts your color pickers (including Developer Color Picker) in your menu bar all the time. If you work with colors a lot, it’s nice for quick access to pickers without having to open a graphics program.


Tools for working with designers

Finally, a couple of shortcuts I use when working with designers.

If your designer gives you hex color values, this is a useful macro that allows you to use them directly rather than converting to HSB or RGB first.

// example usage: [view setBackgroundColor:UIColorFromHex(0x6758c8)];
#define UIColorFromHex(hexValue) [UIColor colorWithRed:((float)((hexValue & 0xFF0000) >> 16))/255.0 green:((float)((hexValue & 0xFF00) >> 8))/255.0 blue:((float)(hexValue & 0xFF))/255.0 alpha:1.0]

Of course, you can use Developer Color Picker to quickly convert the hex value to a UIColor declaration, but I find this method more direct when we’re experimenting and changing colors frequently.

If your designer gives you RGB values, it’s nice to leave the 8-bit values in the code and divide by 255.0 to get the decimal values for the UIColor factory method:

// rgb(103,88,200) is easier to recognize in:
[UIColor colorWithRed:103/255.0 green:88/255.0 blue:200/255.0 alpha:1.0]

// than:
[UIColor colorWithRed:0.405 green:0.344 blue:0.786 alpha:1.0]

Alternatively, you can define a macro to do the same:

// example usage: [view setBackgroundColor:UIColorFromRGB(103,88,200)];
#define UIColorFromRGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0]

Mocking singletons with OCMock

OCMockAlthough Graham Lee might not approve, I occasionally use the singleton pattern, particularly for managing access to my data models.

Singletons in Cocoa are accessed using the following convention:

static UserModelManager *sharedManager = nil;

+(UserModelManager *)sharedManager {
    if (sharedManager == nil) {
        sharedManager = [[super allocWithZone:NULL] init];
    }
    return sharedManager;
}

This makes it challenging to unit test classes that depend on the singleton. Normally when you test class A which depends on class B, you can pass A a mocked instance of B, configured appropriately for the test. But if B is a singleton, A’s only way to instantiate it is through that sharedB instantiator, so your test gets the one and only real instance of the singleton.

There are certainly singleton-ish ways to design around this constraint, but even if your classes don’t use the singleton pattern, you almost certainly depend on one of the singleton classes in the iOS API, like UIApplication or NSNotificationCenter.

Enter categories

The simplest way around this problem is to create a category on the singleton in your test code that overrides the singleton instantiator. In Objective-C, a category is mechanism for adding or overriding methods in existing classes. Using a category, we can modify the behavior of the defaultCenter method just within the scope of the unit tests to return a mock version:

static NSNotificationCenter mockNotificationCenter = nil;

@implementation NSNotificationCenter (UnitTests)

+(id)defaultCenter {
    return mockNotificationCenter;
}

@end

With this category, any time the code under test calls [NSNotificationCenter defaultCenter], it will get value of mockMotificationCenter instead. If you do nothing, it’ll be nil, so it effectively just becomes a message sink. But your test can create a mock using OCMock that expects the notification and verifies that it is issued:

-(void)testShouldPostNotification {
    mockNotificationCenter = [OCMockObject mockForClass:[NSNotificationCenter class]];
    [[mockNotificationCenter expect] postNotificationName:@"some notification"];
   
    [myObject doSomethingThatPostsNotification];
   
    [mockNotificationCenter verify];
    mockNotificationCenter = nil;
}

Note that with this approach, you need to be sure to set the mock instance to nil at the end of your test. OCMocks are autoreleased, so if the test case still has a reference to the released version, you’ll get an EXC_BAD_ACCESS error the next time [NSNotificationCenter defaultCenter] is called. A good place to do that is in your tearDown method, so it’s set back to nil after each test.

Making the mock available to other tests

Now that we can mock the singleton in a single test case, we should make it available to all of our unit tests. I have a base test case class that all of my test classes inherit from, which is where I import OCMock and OCHamcrest and do other global testing setup. We can move the static variable and category up to that class, and create static methods for setting the variable:

+(id)createMockNotificationCenter {
    mockNotificationCenter = [OCMockObject mockForClass:[NSNotificationCenter class]];
    return mockNotificationCenter;
}

+(id)createNiceMockNotificationCenter {
    mockNotificationCenter = [OCMockObject niceMockForClass:[NSNotificationCenter class]];
    return mockNotificationCenter;
}

These methods both set the static variable and return the mock to the caller, for setting expectations and verifying. The “nice” version will silently swallow unexpected messages, where the regular version will throw an exception if it receives an unexpected message. Don’t forget to set it back to nil in tearDown, and call [super tearDown] in the test class’s tearDown method. Now we can update the test case above to:

-(void)testShouldPostNotification {
    mockNotificationCenter = [BaseTestCase createMockNotificationCenter];
    [[mockNotificationCenter expect] postNotificationName:@"some notification"];
   
    [myObject doSomethingThatPostsNotification];
   
    [mockNotificationCenter verify];
}

But sometimes I want the real NSNotificationCenter

The main drawback to this category is that it will always override the original. That may not be an issue for notifications, but when testing your own singletons, you’ll need to be able to test the actual class. But now that you’ve overridden the instantiator in a category, you can’t just call the original instantiator if the static variable is nil. Or can you? Fortunately, Matt Gallagher created some nice macros that you can use to conditionally invoke the original.

Using Matt’s invokeSupersequentNoArgs macro, we can change the category method to the following:

@implementation NSNotificationCenter (UnitTests)

+(id)defaultCenter {
    if ([BaseTestCase mockNotificationCenter] != nil) {
        return [BaseTestCase mockNotificationCenter];
    }
   
    return invokeSupersequentNoArgs();
}

@end

Note we also have to add a class method to retrieve the mock:

+(id)mockNotificationCenter {
    return mockNotificationCenter;
}

Now when [NSNotificationCenter defaultCenter] is invoked, the test case first checks to see if a mock has been set. If it has, the mock is returned. Otherwise, the original, overridden method is invoked.

Conclusion

The singleton is a design pattern you should use with care, as it certainly makes you jump through a few more hurdles when testing. But with a bit of careful setup, your singleton dependencies can (and should) be tested and verified.

Declarative logging in Objective-C

google_analytics.png

I’m currently working on a project with a requirement to log various events using Google Analytics. I created a UsageLogger service to encapsulate all the GA logic and make it easy to turn it off or replace it with another analytics solution.

But I didn’t want to have logging methods sprinkled throughout the code, and don’t want to couple my classes with an analytics package, or even with my custom logger class, so I looked into ways to set up declarative logging.

The approach I landed on uses method swizzling to keep all the analytics logic in my UsageLogger class. One cool aspect of Objective-C’s dynamic runtime is that you can replace the implementation of a method on an individual instance of an object, or on all instances, at runtime. Among other things, this is useful for unit testing.

My approach starts with the following function, adapted from Kevin Ballard’s post on swizzling cocoa methods:

void SwapMethods(Class aClass, SEL orig_sel, SEL alt_sel, BOOL forInstance) {
    if (aClass != nil) {
        Method orig_method = nil, alt_method = nil;
        if (forInstance) {
            orig_method = class_getInstanceMethod(aClass, orig_sel);
            alt_method = class_getInstanceMethod(aClass, alt_sel);
        } else {
            orig_method = class_getClassMethod(aClass, orig_sel);
            alt_method = class_getClassMethod(aClass, alt_sel);
        }
        // If both are found, swizzle them
        if ((orig_method != nil) && (alt_method != nil)) {
            method_exchangeImplementations(orig_method, alt_method);
        } else {
            NSLog(@"SwapMethods Error: Original %@, Alternate %@",
                  (orig_method == nil)?@" not found":@" found",
                  (alt_method == nil)?@" not found":@" found");
        }
    } else {
        NSLog(@"SwapMethods Error: Class not found");
    }
}

The effect of this function is that the pointers to the underlying method implementations are swapped within the class definition. When an object receives a message matching the original selector, the replacement method is invoked instead. And since the implementations are swapped, the replacement selector can be called to invoke the original method.

With this in place, I do the following to intercept the method calls to be logged:

  1. Create a category method matching the signature of the method to be logged.
  2. In the category method, invoke the category method. Once the implementations are swapped, this will cause the original method to be invoked.
  3. In the category method, send a message to the UsageLogger with the information to be captured.
  4. In the UsageLogger’s initialization, call SwapMethods to swap the pointers of the original and category methods.

The code

First, the category method. To keep things clean, I put this in my UsageLogger class:

@implementation TextEntryController (UsageLogger)

-(void)logTextEntered:(NSString *)text {
    // call original (pointer to that method has been swapped with this one)
    [self logTextEntered:text];
    // log the event
    [[UsageLogger sharedLogger] logEvent:@"text-entered" withValue:text];
}

@end

This category adds the logTextEntered: method to the TextEntryController class.

Next, swap the method implementations:

+(void)setUp {
    SwapMethods([TextEntryController class],
                 @selector(textEntered:),
                 @selector(logTextEntered:), YES);
}

After calling [UsageLogger setUp], when an instance of TextEntryController is sent a textEntered: message, the logTextEntered: method is invoked instead. Likewise, when logTextEntered: calls logTextEntered:, the textEntered: method is invoked.

Using Objective-C blocks to log Core Data entities

Usually when I want to log the Core Data entities returned by a query in a particular context, I just passed the object to a log statement, like so:


NSLog(@"Query returned %@", theCoreDataObject);

This works OK when you just have one object to log, but if you want to log the whole array of entities, it gets ugly:

“<MyEntity: 0x4d8d680> (entity: MyEntity; id: 0x4d760a0 <x-coredata://8D01CA08-1D17-4536-844E-EFFDC8539074/MyEntity/p869459> ; data: <fault>)”,
“<MyEntity: 0x4d708b0> (entity: MyEntity; id: 0x4d66e10 <x-coredata://8D01CA08-1D17-4536-844E-EFFDC8539074/MyEntity/p869460> ; data: <fault>)”,
“<MyEntity: 0x4d78a70> (entity: MyEntity; id: 0x4d8c030 <x-coredata://8D01CA08-1D17-4536-844E-EFFDC8539074/MyEntity/p869461> ; data: <fault>)”,
“<MyEntity: 0x4d7ba90> (entity: MyEntity; id: 0x4d03af0 <x-coredata://8D01CA08-1D17-4536-844E-EFFDC8539074/MyEntity/p869462> ; data: <fault>)”,
“<MyEntity: 0x4d7bae0> (entity: MyEntity; id: 0x4d0c660 <x-coredata://8D01CA08-1D17-4536-844E-EFFDC8539074/MyEntity/p869463> ; data: <fault>)”,
“<MyEntity: 0x4d7bc80> (entity: MyEntity; id: 0x4d76900 <x-coredata://8D01CA08-1D17-4536-844E-EFFDC8539074/MyEntity/p869464> ; data: <fault>)”

What am I supposed to do with that, particularly when the data has faulted? If it didn’t fault, the output is even more verbose. I could do something like this to just get the data I’m interested in:

for (id theCoreDataObject in results) {
   NSLog(@"Query returned %@ (%.1f)",
                  [theCoreDataObject someField],
                  [[theCoreDataObject someOtherField] floatValue]]);
}

But who wants multi-line log statements littering their code? Since I’m trying to log the same type of array in a few different places, a closure (or block, in Objective-C terms) seemed like a perfect solution. Here’s the block definition:

NSString* (^formatMyEntity)(NSArray *) = ^(NSArray *entities) {
    NSMutableArray *output = [NSMutableArray arrayWithCapacity:[entities count]];
    for (id entity in entities) {
        [output addObject:[NSString stringWithFormat:@"%@ (%.1f)",
                          [entity someField], [[entity someOtherField] floatValue]]];
    }
    return [output componentsJoinedByString:@", "];
};

To use it, I can just call the block formatMyEntity() like a function:


NSLog(@"Query returned %@", formatMyEntity(results));

And the output is much nicer:

Query returned: for (4), place (4), in (2), price (2), value (2), with (2)

Log userInfo, not localizedDescription, for CoreData errors

Most of the Core Data code samples out there log [error localizedDescription] on errors. However, that will return a message that isn’t particularly useful, like:

The operation couldn’t be completed. (Cocoa error 1570.)

Instead, if you log [error userInfo], you’ll get a much more actionable message, like:

 {
    NSLocalizedDescription = "The operation couldnU2019t be completed. (Cocoa error 1570.)";
    NSValidationErrorKey = timestamp;
    NSValidationErrorObject = "<QueuedOperation: 0x920b100> (entity: QueuedOperation; id: 0x920c700 <x-coredata:///QueuedOperation/t60E29330-FD70-4E70-B5AB-CC7C234FF70965> ; data: {n    identifier = 432;n    timestamp = nil;n    type = 1;n})";
}

From that error, I can immediately tell that the object didn’t pass validation because the timestamp field was nil. When your users start reporting some obscure error, this kind of detail can be critical to troubleshooting.