Quantcast
Channel: iOS/Web Developer's Life in Beta » Michael Nachbaur
Viewing all 13 articles
Browse latest View live

Back to Basics: Using KVO

$
0
0

One of the things I like most about Apple’s iOS SDK is the consistent and easy-to-use API they provide.  Across all their different frameworks there’s a pattern at work that makes using their classes easy to understand.  This is due in part to the simplicity for configuring those objects.  In most cases you don’t need to call cryptic methods to setup or teardown classes.  If you want to change a label’s font, you just set a property.  If you want to add a new set of tabs to a UITabBarController, you simply have to assign an array of view controllers to the “viewControllers” property and away you go.

This up front simplicity comes at a cost however: somebody had to write code to intercept the setting of those properties and update the view to reflect the changes made.  Fortunately for those developers at Apple, Cocoa and Cocoa Touch makes this simple through the use of Key-Value-Observing (KVO).  If you know how to use it, you can do the same thing in your applications as well.  Read on to see what I do to make implementing KVO in my projects easy and intuitive.

What is Key-Value-Observing?

Key-Value-Observing, or more commonly KVO, is a mechanism by which you can observe changes to keys and their values bound to an object.  It lets you make arbitrary objects aware of changes made to values in other objects that are important to you.  When those values are changed at all, the observeValueForKeyPath:ofObject:change:context: method is invoked on the listener, or “observer”.  In essence, it lets you listen to when people change properties on your object.

You might say “Really? That’s all it does? I can get the same by creating a custom setter!” and you might be right, but there’s several reasons why creating custom setters to handle update logic might be undesirable:

  1. It’s easy to create one or two custom setters, but quite tedious if you have lots of properties you want to observe.
  2. Custom setters only work if you are monitoring properties under your control, but impossible if you want to monitor changes made to other objects you encapsulate.
  3. You have to implement your own retain/release/copy cycles manually, instead of simply using @synthesize.
  4. You have to manually keep track of what the old and new values of a property, if they’re important to you.
  5. Your code looks like dog food.

Using KVO in a class essentially buys you flexibility and easy-to-read code, and with a few general practices can be made easy to read and easy to extend.

Setting up KVO the hard way

Many developers getting started with KVO, myself included, typically start by assigning observers for one or two keyPath properties in either their init or viewDidLoad methods.  Then, within their observeValueForKeyPath:ofObject:change:context: method they will have code to respond to those setting changes.

As an example lets assume we’re creating a UIView subclass that has a UIColor property that controls the display of several subviews.

@property (nonatomic, copy) UIColor *color;

When that property changes lets make our view update all our sub-views to the appropriate color. We could do this with a custom setter, like so:

- (void)setColor:(UIColor *)color {
    if (color != color) {
        [color release];
        color = [color retain]; 
 
        mTitleLabel.textColor = color;
        mDescriptionLabel.textColor = color;
        [mButton setTitleColor:color
                      forState:UIControlStateNormal];
    }
}

For the purposes of this example though, lets utilize KVO for this.

- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) {

        [self addObserver:self
               forKeyPath:@"color"
                  options:0
                  context:nil];
    }
}
 

- (void)observeValueForKeyPath:(NSString*)keyPath
                      ofObject:(id)object
                        change:(NSDictionary*)change
                       context:(void*)context
{
	if ([keyPath isEqualToString:@"color"]) {
        mTitleLabel.textColor = self.color;
        mDescriptionLabel.textColor = self.color;
        [mButton setTitleColor:self.color
                      forState:UIControlStateNormal];
	}
 
    else {
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
    }
}

In the initWithFrame: method we add ourselves as an observer of the keyPath “color”, passing in the default options.  We also define a method that Cocoa Touch uses to notify the observer, in this case “self”, when a keyPath has been changed.  This method is invoked for different properties that are changed, so you should always pass the message along to “super” if this method is called for a property you didn’t explicitly add as an observer.

While the above code does look longer than the custom setter equivalent, in the long-run this code is much easier to extend over the life of your class, especially as you add more complex behaviors.

Keeping Track of Your Key Paths

As my experience with KVO improved, so did my techniques for managing my observers, responding to keyPath value changes, and generally keeping my code clean.  One of the things I found was that it is useful to keep a list of the keyPaths you’re observing so that you can conveniently iterate over them programmatically.

To illustrate my point, consider an example where you expose multiple subviews as properties, and when some values change you would like to perform some sort of redraw operation.

- (id)initWithFrame:(CGRect)frame {

    if (ObservableKeys == nil) {
        ObservableKeys = [[NSSet alloc] initWithObjects:
                          @"titleLabel.font",
                          @"descriptionLabel.font",
                          // ...
                          nil];
    }
 
    self = [super initWithFrame:frame];
    if (self) {

        for (NSString *keyPath in ObservableKeys)
            [self addObserver:self
                   forKeyPath:keyPath
                      options:0
                      context:nil];
    }
}
 

- (void)dealloc {
    for (NSString *keyPath in ObservableKeys)
        [self removeObserver:self
                  forKeyPath:keyPath];
    [super dealloc];
}
 


- (void)observeValueForKeyPath:(NSString*)keyPath
                      ofObject:(id)object
                        change:(NSDictionary*)change
                       context:(void*)context
{
    if ([ObservableKeys containsObject:keyPath]) {
        [self redrawView];
	}
 
    else {
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
    }
}

As you can see not only would this be impossible to do with custom setters, but we managed to respond to several different property changes using a single block of code.

Additionally, keeping a static NSSet object around with a list of the keys you’re observing is convenient for several reasons:

  1. It lets you easily add your object as an observer of several keyPaths without having to copy/paste code.
  2. Your generated code is tighter because you don’t have to worry about inline strings being littered throughout your class.
  3. If you change the name of a keyPath, it happens in a much more limited area.

There are other advantages, but this is just the tip of the iceberg.

Implementing KVO in a UITableViewCell Subclass

In order to illustrate how to build a more complicated feature using KVO, lets create a UITableViewCell subclass that makes it easy to create a gloss icon in your table cells, just like the iTunes App Store app.  If we’re successful we should be able to create a table cell whose icon looks like the screenshot to the right.

Instead of requiring us to worry about the details of rendering the gloss icon overlay every time we want to display an app icon, lets create a property on our table cell that encapsulates this behavior.  Ideally we should be able to set the app icon’s original image once, and the UITableViewCell imageView.image property should be set to the appropriate content.  We could do this with a custom accessor, but I’d like to show you an easy way to do this with KVO.

#import <UIKit/UIKit.h>
 
@interface AppStoreItemView : UITableViewCell
 
@property (nonatomic, retain) UIImage *icon;
@property (nonatomic) BOOL iconNeedsGlossEffect;
 
@end

You can see from our interface declaration that we’re adding two properties for the icon image itself, and a boolean indicating whether or not we want the gloss effect.  Now lets look at the implementation.

#import "AppStoreItemView.h"
#import <QuartzCore/QuartzCore.h>
 
static NSSet * ObservableKeys = nil;
static NSString * const IconKeyPath = @"icon";
static NSString * const IconNeedsGlossEffectKeyPath
    = @"iconNeedsGlossEffect";
 
@interface AppStoreItemView ()
 
- (UIImage*)glossImageForImage:(UIImage*)image;
 
@end
 
@implementation AppStoreItemView
 
@synthesize icon;
@synthesize iconNeedsGlossEffect;
 
- (id)initWithStyle:(UITableViewCellStyle)style
    reuseIdentifier:(NSString *)reuseIdentifier
{
    // Setup our set of observable keys only once
    if (nil == ObservableKeys) {
        ObservableKeys = [[NSSet alloc] initWithObjects:
                          IconKeyPath,
                          IconNeedsGlossEffectKeyPath,
                          nil];
    }
 
    self = [super initWithStyle:UITableViewCellStyleSubtitle
                reuseIdentifier:reuseIdentifier];
    if (nil != self) {
        // Add observers for each of the keyPaths we care about
        for (NSString *keyPath in ObservableKeys)
            [self addObserver:self
                   forKeyPath:keyPath
                      options:(NSKeyValueObservingOptionOld |
                               NSKeyValueObservingOptionNew)
                      context:nil];
         
        self.imageView.layer.cornerRadius = 10.0;
        self.imageView.layer.masksToBounds = YES;
    }
     
    return self;
}
 
- (void)dealloc {
    // Tidy up and remove all the observers when the view is destroyed
    for (NSString *keyPath in ObservableKeys)
        [self removeObserver:self
                  forKeyPath:keyPath
                     context:nil];
     
    [super dealloc];
}
 
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    // If the keyPath being changed isn't one we care about,
    // pass this up to super and return immediately.
    if (![ObservableKeys containsObject:keyPath]) {
        [super observeValueForKeyPath:keyPath
                             ofObject:object
                               change:change
                              context:context];
        return;
    }
     
    // Fetch the old and new objects from the change dictionary
    id oldObject = [change objectForKey:NSKeyValueChangeOldKey];
    id newObject = [change objectForKey:NSKeyValueChangeNewKey];
     
    // Detect null values, since the changed object references
    // are object references.
    if ([NSNull null] == (NSNull*)oldObject)
        oldObject = nil;
    if ([NSNull null] == (NSNull*)newObject)
        newObject = nil;
     
    // Update imageView when the icon is changed
    if ([IconKeyPath isEqualToString:keyPath]) {
        self.imageView.image = [self glossImageForImage:newObject];
    }
     
    // If the gloss effect is changed, refresh the gloss image
    else if ([IconNeedsGlossEffectKeyPath isEqualToString:keyPath]) {
        self.imageView.image = [self glossImageForImage:self.icon];
    }
}
 
- (UIImage*)glossImageForImage:(UIImage*)image {
    // Code goes here to create the gloss image
    // and return the resulting image.  See the
    // sample code for the full example.
    return mergedImage;
}
 
@end

This code may seem complicated, but in the end it is very straight-forward. I’m also introducing a few additional concepts here that I’d like to call out specifically.

Observing Options

KVO allows you to specify different options for when you’re observing a set of keyPaths. It’s a bit-mask, so you can enable multiple options simultaneously.  In this example I’m indicating that I want to be notified of both the old and new values of these properties.  When the icon is changed, the change dictionary supplied to our callback tells us both the old and new values of the property.

Using static strings for keyPaths

This is a pattern I use which helps for simplicity of code, as well as a defensive coding mechanism. By declaring static NSString variables for each keyPath you’re observing, it ensures you won’t accidentally type the wrong keyPath somewhere in your code. It also gives you a single place for defining, or changing, the keyPath you’re interested in observing.

Returning early from the observer callback

In this example I’m returning early in the block, when the keyPath is not in my set of “ObservableKeys”. This makes the callback code cleaner since you eliminate one extra nested “if” block, and helps to prevent mistakes.

Detecting null values in the observer callback

I find it useful to extract values from the change dictionary as early as possible, and then cast those values as needed.

Using private methods for observer callback behaviour

If you’re not careful your observer callback can get quite large.  It’s powerful to be able to have a single point where complex behaviours and patterns can be established between different properties, but you should make sure it doesn’t become overgrown with logic. It’s better to start out by pushing complex logic into private methods, and simply invoke that from within your callback.

Where to go for help

Apple’s own documentation, as always, is a good source of information but it can tend to be a lot to take in.  At this point you should have a basic understanding of how KVO works, and how you can use it in your application.  You can also download the sample application created above at Github.

Once you get started, finding answers to your questions becomes simpler when you’ve gotten the hang of KVO.  Good luck, and happy coding!


Using GCD and Blocks Effectively

$
0
0

With iOS 4.0 Apple introduced two new technologies to the iOS platform: Grand Central Dispatch, and blocks.  Simply put, it is to multi-threaded programming what fire is to a barbecue.  Sure you can do without it, but the end result is much better.

Despite all this, developers still seem to avoid using it. Some of the reasons for this, off the top of my head, could be backwards-compatibility for older versions of iOS, unfamiliarity with the funky syntax it uses, or simply a lack of practice.  The biggest thing I find however is a general misunderstanding about the importance of multi-threading among new developers, which was made worse by the difficulty of dealing with threads before blocks and GCD was released.

Fortunately there’s no reason to avoid multi-threaded programming in iOS, but before I dive into the specifics I’d like to point out just how important it is to use an asynchronous approach to development on iOS, or any mobile platform in general.

Why should I care about GCD?

Before going into the specifics of how to use blocks and Grand Central Dispatch, I’d like to explain why it’s important. If you don’t take anything else away from this article, these points are important.  Here it goes:

Don’t make the device wait around for you to figure out what you want it to do.

The CPUs in mobile devices are really weak, memory is limited, you have some really hard limitations that you just can’t work around.  Performance problems aren’t often caused by a single slow operation, but many inefficiencies in how you utilize the hardware.  Performing expensive calculations, querying a database, reading images from disk, or other activities all take time.  Are you using caches effectively? Are you performing expensive tasks in the main thread?  There are many other things that you may be doing that can block the CPU from doing what really needs to happen: Rendering your interface to the screen 60 times per second.  If you can’t meet that target, your app is failing to provide smooth animations, and it will stick out like a sore thumb compared to the other applications on the device.

Each thread on your device runs its own event loop.  The operating system picks up a page of code, runs it, and when that chunk of code exits out the next iteration of the loop picks up.  When rendering your display, the main thread wakes up, runs all the code necessary to assemble your UI, paints a picture onto a memory buffer, and throws that on the screen. It tries to do this 60 times per second.  If each iteration of this runloop takes more than 16ms to run, then your device will drop frames and your display will get jittery.  If it takes less than 16ms, this means there’s spare CPU cycles available to do other work.

The basics of asynchronous programming

Developers in general are quite lazy; in fact, laziness is a great virtue to have as a programmer.  It means we’d rather be doing something else, so we want to do as little work as possible so we can get on with other work.  So it’s quite understanding why so many applications are developed with lots of synchronous code: It’s just easier to think about problems in a linear fashion.  You break a problem down into a series of steps, and write the code necessary to do those steps in order. Fortunately for us most computers are fast enough that this technique works well.  But once you switch to a mobile platform, long linear functions need to be broken down into smaller steps.

Consider an example where you download an image over the network, you resize and scale it to a thumbnail, and then put it onto the screen.  Because any operation interacting with the UI must be performed on the main thread, the easy route is to do all the above as a single synchronous set of instructions on the main thread.  Doing so however will result in the UI freezing up during the download, image conversion, and image resizing operations.

// Download the image
NSURL *url = [NSURL URLWithString:@"http://bit.ly/nUX01h"];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLResponse *res = [[NSURLResponse alloc] init];
NSError *err = nil;
NSData *data = nil;
data = [NSURLConnection sendSynchronousRequest:req
                             returningResponse:&res
                                         error:&err];

// Convert the data to a UIImage
UIImage *image = [UIImage imageWithData:data];
      
// Scale the image
UIImage *thumbImage = nil;
CGSize newSize = CGSizeMake(90, (90 / image.size.width) * image.size.height);
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
thumbImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
 
// Add this to a UIImageView
self.imageView.image = thumbImage;

Not only is converting the image from data to a UIImage or scaling the image to a  thumbnail expensive, but depending on the speed of the user’s network (e.g. wifi, 3G, AT&T, etc) the download could take significantly longer.  So the best way is to break this up into multiple smaller steps. When each step finishes, the system will work on the next chunk.

Taking the above example of what not to do, lets refractor it slightly to use blocks.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSURL *url = [NSURL URLWithString:@"http://bit.ly/nUX01h"];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:req
                                       queue:[NSOperationQueue currentQueue]
                           completionHandler:
     ^(NSURLResponse *res, NSData *data, NSError *err) {
         // Convert the data to a UIImage
         UIImage *image = [UIImage imageWithData:data];
          
         // Scale the image
         UIImage *thumbImage = nil;
         CGSize newSize = CGSizeMake(90, (90 / image.size.width) * image.size.height);
         UIGraphicsBeginImageContext(newSize);
         [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
         thumbImage = UIGraphicsGetImageFromCurrentImageContext();
         UIGraphicsEndImageContext();
          
         dispatch_async(dispatch_get_main_queue(), ^{
             self.imageView.image = thumbImage;
         });
     }];
});

As you can see most of the code is the same, except we’re breaking things down into smaller discrete chunks.  Each block is nested, allowing code to be called only when it is needed.  I’ll go into more detail with this shortly, but see if you can piece together what’s different between these two samples of code.

Doing the above fully asynchronously without blocks is entirely possible, but results in more complicated code that is more difficult to maintain.  The biggest difficulty is in keeping track of values and properties between threads, and results in a lot more boilerplate code.  Using blocks you can simply access the variables accessible within your current scope, making everything much easier.

What is a block?

Blocks in essence are nested functions that can be passed around as a pointer that has access to variables defined in the scope the block is defined in.  If you have ever worked in a language that supports “closures” (e.g. JavaScript, Perl, etc) you’ll probably already be familiar with this.

Blocks in Objective-C are defined rather strangely, but once you get used to it they make sense.  The carat “^” character is used to define a block. For example, “^{ … }” is a block. More specifically, it is a block that returns “void” and accepts no arguments.  It is equivalent to a method such like: “- (void)something;” but there is no inherent name associated with the code block.

Defining a block that can accept arguments work very similarly.  If you wanted to supply an argument to a block, you define the block like so: ^(BOOL someArg, NSString* someStr) { … }.  When you use API calls that support blocks, you’ll be writing blocks that look similar to this, especially for animation blocks or NSURLConnection blocks as shown in the above example.

The easiest way to get started with blocks is to simply use existing APIs that support them. NSURLConnection above supports blocks, as do UIView animations, like so:

[UIView animateWithDuration:1.0
                 animations:^{
                     someView.alpha = 0;
                     otherView.alpha = 1;
                 }
                 completion:^(BOOL finished) {
                     [someView removeFromSuperview];
                 }];

If you have any experience with animating views without blocks, getting a completion handler to run after an animation has completed is extremely cumbersome, so much so that many developers don’t bother with them. Using the block-enabled alternative makes for much cleaner code, and makes it fun to create complex animations.

How does GCD tie into this?

Grand Central Dispatch is a facility for managing threads and queueing tasks in parallel efficiently, without you needing to worry about the boilerplate specifics around performance and startup / shutdown of threads.  Blocks and GCD are both completely different technologies, but since they work so well together it’s trivial to get started with it.

In order to use GCD, you use one of the functions that begin with “dispatch_“.  One of the common tasks a developer would want to perform is to run some small task in a background thread, and then run some other code on the main thread once that task has completed.  You may notice the call to “dispatch_async” up above, which explicitly runs a block on the main thread.

Dispatching blocks can either be triggered synchronously or asynchronously by using the dispatch_sync or dispatch_async functions, and they both take two arguments: The queue you want to dispatch your block on, and the block you’d like to dispatch.  Individual queues are analogous to threads, but the specifics about which thread your code will be run on is hidden from you, meaning the operating system can optimize the use of threads based on the number of cores your system possesses.

The two most common ways you’d get a pointer to a queue is to either fetch the main queue using “dispatch_get_main_queue()” or to fetch a queue with a specific priority, you use dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) and specify the priority you’d like (DEFAULT, LOW, HIGH, or BACKGROUND).

How do I create my own block APIs?

The most difficult part of dealing with blocks for many people is how to define your own methods or APIs that utilize blocks, mostly due to the confusing syntax used to define them.  Once you figure out how the syntax is broken down however, it’s quite easy.  Let me start with a few examples.

So first, let me show you how to define a block that takes no arguments and returns nothing.

- (void)noArgBlock:(void (^)(void))block;

The syntax we’re concerned about here is in the definition of the “block” argument.  As you know, you declare the type of an argument in parenthesis immediately before the name of the attribute.  So it’s easiest to ignore those outer parenthesis when dealing with block definitions.

void (^)(void)

Now things are looking a little more straight-forward, and a little closer to a standard C function.  The first word is the return type we expect a block with this definition to return.  Since we said we were creating a basic block that returned nothing, this is set to “void“.

Normally in a C function definition the very next thing after the return type would be the function name.  But since blocks aren’t actually named, instead we use “(^)” to denote that it’s an unnamed block that we’re defining.  So far so good, right?

Finally we define the parameters this block will accept.  Again with regular C functions this should be familiar, since you give a parenthesized list of arguments you’ll be providing to this function.  Since we’re not accepting any arguments to this block, we indicate that by putting in “void“.

And that’s it! Lets show you how you’d use that in your function!

- (void)noArgBlock:(void (^)(void))block {
    // Do something...
     
    // Call our block
    block();
}

When you want to invoke a block function supplied to your method, you can just call it like you would any C function.  But what if we want to call that block on a different queue or thread?  That’s easy enough too.

- (void)noArgBlock:(void (^)(void))block {
    // Do something...
     
    // Call our block
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), block);
}

We’re using the GCD dispatch function here to trigger our block asynchronously on a low-priority queue.  Blocks can be passed around as variables, so we don’t have to explicitly define our own inline block here like we did in the animation or image examples at the beginning of this article.

Armed with all that syntax in mind, lets create a block that accepts an argument, and I’ll show you how to use it.

- (void)hasArgsBlock:(void (^)(NSString *name, BOOL animated))block {
    block(@"FOO", NO);
}

Remember from what I said that the second set of parenthesis in a block definition is the argument list you’ll be supplying to the block.  In this case, we’re accepting a callback that takes an NSString and a BOOL argument.  This is a contrived example since we’re simply dispatching the block immediately, but we could just as easily include our block call in our own block callback as the result of a UIView animation, an NSURLConnection completion block, or anything else.  A user of this method could look like this:

[self hasArgsBlock:^(NSString *name, BOOL animated) {
    NSLog(@"Name: %@, animated %d", name, animated);
}];

How do I store a block as an ivar?

This is a much trickier question, and is one of the things that makes people run screaming from blocks, assuming they didn’t already do so when they saw the “void(^)(void)” syntax soup.  Consider the example where you want to store a block for later use, or re-use.  If we want to store a void block, a simple solution is to use a built-in GCD type to reference blocks.

The dispatch_block_t type can be used.

@interface MyViewController : UIViewController {
    dispatch_block_t _simpleBlock;
}
 
@property (nonatomic, copy) dispatch_block_t simpleBlock;

If you want to store a block that either accepts arguments or returns a value, it’s possible to use the block-parenthesis-soup as the type definition for an ivar.  For example, assume we want an ivar named “completionBlock” defined within our class. We can do so with the following code:

@interface MyViewController : UIViewController {
    void (^completionBlock)(NSString *name, BOOL animated);
}

However that looks hideous, and is difficult to maintain. Instead it’s in your best interest to define your own custom type based on the block-soup you’d use in a method declaration. If we wanted to create a typedef for our above block, the one that accepts a name and animated property.  We could do so with the following declaration.

typedef void (^MyCompletionBlock)(NSString *name, BOOL animated);

By including a name after the carat symbol you can assign the block definition a name.  Then, later, you can use that typedef in an ivar, in a property, or even as an argument to another method.

@interface MyViewController : UIViewController {
    MyCompletionBlock _completeBlock;
}
 
@property (nonatomic, copy) MyCompletionBlock completeBlock;
 
- (void)storeMyBlock:(MyCompletionBlock)block;

Since blocks are objects, you need to copy them if you want to store them as a property, and don’t forget to release them when you’re done with them, or in your class’ dealloc method.

Closures, variables, and retain cycles

As I mentioned above, blocks work as closures, meaning you have access to the local variables within the scope a block is defined in.  This makes your code really easy to work with, but there are some limitations that are imposed for some very good reasons.  Consider the following example:

NSArray *someArray = ...;
int myCount = 0;
[someArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    int someValue = [obj intValue];
    myCount += someValue;
}];

This is a great way to perform an operation against an array or set using blocks because it will take advantage of multiple cores to be able to run your code faster when it’s possible.  However the above code won’t work if you actually tried it, because there’s a specific limitation in blocks which prevent you from writing to values declared outside of the block.  Think of it as a thread-locking problem. If you were to build that above code, you’d get an error that says “Variable is not assignable (missing __block type specifier)”.

It’s simple enough to work around this.  You can use the “__block” flag when declaring a variable so you can allow it to be writeable from within a block.  For example, the above code could just have this one change and everything would work as you’d expect:

__block int myCount = 0;

One other gotcha is regarding retain cycles when using the special “self” variable.  In the case where you retain a block and, within that block you refer to your “self” object, this will cause an unbroken retain cycle where the block is retained by self, and “self” is retained by the block.

self.completionBlock = ^(NSData *result) {
    [self saveFile:result];
};

This little block will take some data returned from some code and save it in some way.  However because the “self” variable is retained by the block, as well as the scope outside of the block, this block will leak memory.  Yet again, this is easily solved by declaring a “weak” reference to the self variable, and then using that within the block.  If you’ve ever worked in JavaScript you’ll be familiar with this pattern.  The resulting code would look like the following:

__block __typeof__(self) _self = self;
self.completionBlock = ^(NSData *result) {
    [_self saveFile:result];
};

Bringing it all together

Blocks are an extraordinary enhancement to the language, and if you take full advantage of it in your applications you’ll be able to seamlessly take advantage of faster language features, your code can spread across multiple cores seamlessly, and you can easily break serialized tasks into fast divisible units of labour.

Take a look through the various block APIs that Apple supports, and embrace it as much as you can.  In the long run it’ll make your code easier to understand, and faster as technology advances.  Don’t be left behind!

Building a static library with Jenkins

$
0
0

One of my pet peeves is Open Source iOS libraries distributed as just a collection of Objective-C classes, rather than being bundled as a static library. I know a lot of people prefer it that way, but from a maintainability standpoint it really doesn’t make much sense to me. So when I’m faced with another library I want to use that doesn’t have a static library readily available for it, I typically wrap it up in my own Xcode project, check it in to Github, and configure my Jenkins continuous integration build server to compile it for me.

I thought I’d walk you through the steps I go through to make this happen, so you can use this technique too.

Why I prefer static libraries

Before I go too far on this topic I wanted to explain my reasoning behind preferring static libraries, as opposed to loosely-distributed sets of classes.

Consider a large project where I’m utilizing a few libraries built by third-parties to speed up my development; a recent example of this on one of my projects is using the AFNetworking library from Gowalla. Now I could simply sync their source tree from Github, drag-n-drop their classes into my project, and I could be done with it. But what happens when one of their classes is upgraded? I have to re-sync the code, resolve any differences, and drag it back into my project.  I could of course make their project a git sub-module of my own, but then whenever I perform an update to my git project I may not know which changes their source has undergone, meaning I have no control whether or not my project will pass or fail.  And this assumes I’m using Git for my project; at work we use Perforce which has terrible Git integration.

Assuming I have an up-to-date set of classes from a third-party integrated into my project, what happens in the event I change some C pre-processor definitions that break those classes? Since every time I compile my code I have to also compile the third-party code, I don’t know if a compilation bug in the third-party classes are a problem caused by my build settings, or is a problem in their code.  If I were to consume a static library I could re-use that binary safe in the knowledge that no random changes will take place in it.  If I wanted to bring in any updates from a third-party I can choose when to integrate those updates in since I can choose when to copy over the new library.

And finally, the reason why I had to create a static library for AFNetworking in the first place, is in the transition from manual reference counting to “Automatic Reference Counting” (also known as ARC).  ARC requires actual code-level changes since such method calls as “release”, “autorelease”, “dealloc” etc are now a compilation error.  This means you can’t mix-and-match ARC and non-ARC classes in the same project.  Non-ARC code compiled in its own separate static library though can still play nice within a different ARC project.

How to create a static library

First you should begin by either forking the target library on Github, or by acquiring the source code in some other way. If you fork from Github it will make it easier to merge changes down later as the project is updated in the future, or provides for the ability to merge your static library up into the main project.

Regardless, once you get the code you begin by creating a new static library project in Xcode. It’s simple enough; just make sure you select the “Cocoa Touch” static library project and you should be good to go.  Once this opens up it will give you some boilerplate classes and settings; feel free to delete those.  You might want to create the new project somewhere within the source tree for the library in a way that won’t annoy other developers.  For example, you might not want to move the original classes around too much since it might make it difficult for other developers to merge your change into their own branches.

Once you have your empty library project you can go ahead and add all the classes you’ll be wanting to include in the library, either by using the “Add files to…” menu item, or by drag-and-dropping them from Finder into an appropriate folder in the navigation pane of your project.

At this point the code might compile, but you need to make some changes to the project settings in order to make it possible to compile, and to make it easy for you to get at the built results of the project.  Click on the root of your project to open the project settings, and make the following changes:

  1. Installation Directory (INSTALL_PATH): Set this to “/”. This indicates where the products of the build (namely the static libAFNetworking.a file) will be installed, relative to the target installation root.
  2. Public Headers Folder Path (PUBLIC_HEADERS_FOLDER_PATH): This controls where the public headers for your library will be installed, relative to the installation root. Set this to “Headers”.
  3. Header Search Paths (HEADER_SEARCH_PATHS): This isn’t strictly necessary for all projects, but in this case we’re going to compile against the JSONKit library, but are not going to be including it in the resulting static library. So we need to tell Xcode where to find the header so it can properly compile the classes that might potentially depend on it.
  4. Skip Install (SKIP_INSTALL):Set this to “No” or, in the example in the above screenshot, set delete it so the Xcode default of “No” will take effect. This is important because without this we won’t be able to install the results of this build into a directory where we can get at it.
  5. Precompile Prefix Header & Prefix Header (Optional): In the example I’m showing here I didn’t actually want to add more unnecessary files to the project than needed, and since the prefix header only adds a global import of “Foundation.h”, I removed those from the Xcode project.

Once you get the static library settings configured you can take one final step to control the build phases your library will go through.  The particular build phase we want to configure is the “Copy Headers” build step.  This setting is broken down into three sections: Public, Private, and Project sections. By default all the header files of your project will reside in the “Project” section, meaning those headers will only be available to your project and will not be installed when you complete your build. The other two sections, “Public” and “Private” let you indicate a directory path where you’d like your headers put when it’s installed.

You can see in the screenshot that I’ve moved all of the AFNetworking headers into the Public section, and left JSONKit in the Project section. This is because if a user of this library wants to use JSONKit they’ll presumably get it on their own, so any headers we include here might result in a conflict. So it’s best to just include the headers for the code that is actually present in your project.

If you’re creating an SDK or a reusable API for others to use and there are some parts of your code that you would rather remain hidden, simply don’t move those headers into the “Public” section.

Building your library in Jenkins

At this point your code should compile cleanly when you click the “Build” button. But more than that we want to be able to simplify the compilation of this library so it can easily be packaged up and shipped off.  I like to either use shell scripts or “Ant” to automate my build process since it allows me to predictably run my builds deterministically with little room for human error.

There are several things we want the build script to accomplish:

  1. Create a directory where the results of the build will reside;
  2. Compile versions of the static library for both the device and the simulator;
  3. Create a “FAT” library containing both the device and simulator results for easy debugging;
  4. Create a ZIP file containing the static library and its headers.

#!/bin/sh
set -ex

INSTALL_PATH=$WORKSPACE/artifacts
[ -z $INSTALL_PATH ] || INSTALL_PATH=$PWD/artifacts

rm -rf $INSTALL_PATH
mkdir -p $INSTALL_PATH

PROJ=AFNetworking/AFNetworking.xcodeproj

xcodebuild -project $PROJ -sdk iphoneos INSTALL_ROOT=$INSTALL_PATH/device install
xcodebuild -project $PROJ -sdk iphonesimulator INSTALL_ROOT=$INSTALL_PATH/simulator install

lipo -create -output $INSTALL_PATH/libAFNetworking.a $INSTALL_PATH/device/libAFNetworking.a $INSTALL_PATH/simulator/libAFNetworking.a
mv $INSTALL_PATH/device/Headers $INSTALL_PATH
rm -rf $INSTALL_PATH/device $INSTALL_PATH/simulator
(cd $INSTALL_PATH; zip -r ../AFNetworking.zip libAFNetworking.a Headers)

If you understand Bourne Shell that code should be pretty straight-forward. You simply set up an install path relative to the Jenkins workspace (or relative to your current directory if you’re running the script by hand), run two separate builds using “xcodebuild”, use “lipo” to merge the resulting static libraries, and we create a ZIP file of the resulting files.

I’ll go through each part of the “xcodebuild” command to point out why I’m doing things this way.

  • “xcodebuild -project $PROJ” – Indicate the project file that you want to build. I’m using a variable defined higher up in the script to make it easy to change.
  • “-sdk iphoneos” or “-sdk iphonesimulator” – Manually specifying the SDK to use so we can compile both the device and simulator versions.
  • “INSTALL_ROOT=…” – This passes a variable into the build process, allowing us to customize the path the resulting artifacts will be installed to. By default, as you can see from the above screenshots, that the path “/tmp/AFNetworking.dst” is defined.  This command-line argument lets us override that setting to configure a path of our choosing.
  • “install” – Perhaps the most important part, we’re saying we want to install the files, rather than just simply building them. Xcode normally creates its build artifacts in a folder in ~/Library/Developer/Xcode/DerivedData, keyed off some awfully long UUID, and there’s no easy and deterministic way of identifying the path Xcode will choose when building its artifacts.  When using “install” the appropriate files are copied from that interim build directory and into the directory you selected above.

Getting Jenkins to rebuild when code is checked in

The final and most useful step is to get your code rebuilding automatically when you check new code into Github. This technique will work for other version control systems, but Github is certainly the easiest to control.

Make sure your build script is checked into your source tree, and configure a new job in Jenkins for your static library project. I won’t walk you through the entire process, but it’s simple enough to create a “Freestyle” project, set up your Github credentials for checking code out when a build is triggered.  From there, add a new “Execute Shell” build step, and add the following to the command:

“$WORKSPACE/build.sh”

Make sure you include the quotes, because your $WORKSPACE path that Jenkins assigns you may potentially contain whitespaces that would break that command.  From there you should be able to trigger a new build manually and have it compile your project for you.  Give it a try and make sure it works.

Next you’ll want to do something with the resulting build artifacts. What I like to do is create a single directory under which all my compiled resources will be collected and archived by Jenkins, but since the above build script created a single convenient ZIP file we can just archive that. Check the “Archive the artifacts” box, and type “AFNetworking.zip” into the field.

At this point we’re finally able to integrate our build into Github, but it’s a lot simpler than you might think.  Jenkins has an amazing REST API that lets you interact with it programmatically. If you want to kick off a new build, all you need to do is perform an HTTP GET against the “build” URL for your job. If your Jenkins server is located at http://jenkins.mycompany.com/ and your job is named “MyLibrary”, you only need to issue a GET to http://jenkins.mycompany.com/job/MyLibrary/build.

With that in mind, go to your “Admin” settings on Github for your project, and click on the “Service Hooks” menu.  Github provides a long list of services it can interact with, but the simplest and most straightforward is the “Post-Receive URLs” section. This lets you supply a list of URLs that Github should issue a request to after it has received a new checkin.

As you can see from the screenshot to the right, it’s fairly simple and is easy to test.  Next time you perform a “git push” back up to Github, your Jenkins server should automatically trigger a new build.

If you want to see everything I’ve talked about here, go to my Github fork of AFNetworking or download the AFNetworking.zip file from my website created from the process I describe above.

Back To Basics: Simple debugging tips in Xcode

$
0
0

As developers we spend most of our lives dealing with broken and barely-functional software: our own software. We do our best to make the applications we develop somewhat less broken and try to add features to make it functional. And once we finally get our software working bug-free and functioning stably, what do we do? Do we bask in the joy of a stable app and spend countless hours enjoying that moment? No, we move on to v1.1 or v2.0, adding more features and consequently more bugs.  It’s kind of sad if you think about it.

Since much of our lives are spent with applications in various states of brokenness, understanding how to debug our software and catch those exceptions that arise is vital to getting our applications to a stable state so we can release, consequently moving on to create a whole new set of bugs that need to be fixed.

Here are some basic tips and tricks to make your life easier dealing with Xcode 4, and tracking down those places where your code runs off into the bushes.

Using breakpoints

Most people are familiar with the concept of breakpoints, but if you’re not I’ll reproduce it here. Click the line number next to a line of code, and a breakpoint icon will show up, causing your application to pause when it gets there.  From that point you can inspect the values of variables within your scope, you can single-step from one line of code to the next, etc. It’s something most web developers wish they had.

Editing breakpoints

You can also edit breakpoints.  Right-click on a particular breakpoint and you can click the “Edit Breakpoint” menu. You also have a few other options available to you, including the ability to disable or delete a breakpoint. However there’s easier ways to do the same things; you can either drag the breakpoint off of the line-number margin, just like removing an icon from your dock, or you can click the line to toggle its “disabled” state.

Conditional breakpoints

When you select “Edit Breakpoint” you are presented with a context menu showing additional options for that breakpoint. You can set a condition that will cause your breakpoint to trigger only when that condition is met, you can cause it to ignore the breakpoint until a certain number of times, and can even trigger complex actions to be performed automatically when that breakpoint is hit.

For example, you can log a line to the console, you can play a sound, you can capture an OpenGL frame for later comparison, and can even invoke a shell script or AppleScript.

Managing your breakpoints

Once you have a lot of breakpoints in your code it can often be difficult to manage it. So in the Xcode 4 navigator pane you can click on the “Breakpoints” tab (or you can press ⌘-6) to see a full list of your current breakpoints.

You can enable or disable the breakpoints right from there, you can delete them, etc. But as you can see, at the bottom of the navigator, there’s a toolbar.  From there you can create new breakpoints, filter breakpoints, and other fun tasks.

The most important feature here however is the ability to add explicit breakpoints without having to have an associated line number.  Clicking the “+” button brings up a menu with two options: “Add Exception Breakpoint” and “Add Symbolic Breakpoint”.

Exception breakpoint

This is perhaps one of the most powerful breakpoints you can have in your debugging arsenal, and is something you’ll almost always want to add to your project. In a nutshell it will cause your program to pause at a line that triggers an exception, rather than simply crashing and burning with an EXC_BAD_ACCESS or some other similar exception.

This makes debugging your code quite a lot easier because instead of seeing a mysterious crash in main.m, or in objc_msgSend, you will see the line of code in your application that resulted in that exception happening in the first place. This is true debugging power because without that bit of context you’d have no other idea about where or why your application is crashing.

Symbolic breakpoints

Symbolic breakpoints are just like regular breakpoints, but instead of catching a particular line of code, you can pause your application when a method or function call is made.  There are some pre-defined symbols you can use, or you can break on a particular method name.  For example, “objc_exception_throw” is a handy symbol to break on since it will capture an exception being thrown, regardless of whether or not it is caught. Another useful breakpoint to set is “-[NSObject doesNotRecognizeSelector:]” which will allow you to capture situations where a selector is being invoked against the wrong object.

There are of course other symbolic breakpoints you can set but there’s too exhaustive of a list to outline them here, so use the Almighty Google for future reference.

Using the debugger console

Once your breakpoint has triggered, your next question may be “Well now what?” What can you do with your code once your program has suspended? The most obvious thing you can do is single-step through the following lines to see what happens, what paths your code takes, and so forth.  But there will be times that you’ll want to deeply inspect properties or ivars in ways that the variable window won’t let you.  For this you can use the debugger console to control the debugger explicitly to find answers to your question “What’s my app doing right now?”

Printing objects

Say for the sake of argument that you’ve got an ivar named “_myDictionary” that contains some object, and you want to print out its default value.  That’s simple, you can click in the console window (the right-hand pane of the bottom debugger panel), and you can type: “po _myDictionary“.  That will print out the result of the -[NSObject description] method for that object.

However lets say you want to dig deeper, and want to print the result of a method call on that dictionary.  This is also simple: “po [_myDictionary allKeys]” works just as well.  The debugger console doesn’t understand Objective-C 2.0 Properties, but regular bracket-notation method calls works.

Printing primitives and structs

What if what you want to print isn’t an object? What if you want to print out the value of a literal (e.g. a float or NSUInteger), a struct (e.g. CGRect, CGPoint, etc), or really anything else that may or may not be an object?  With that you can use the “p” command.  However since you’re not printing an object, you need to give the debugger a hint about what kind of primitive you’re expecting.

To print a float, I would say: “p (float)_myFloatValue“. Simple variable casting here works just great.

Printing out the frame of a view is also pretty simple. “p (CGRect)[[self view] frame]“.  You notice here that I’m combining a set of method calls with a casted print statement. This will give you a pretty-formatted rendition of the rect, making it easier to debug.

Printing CPU registers

When your code is compiled down into machine code and is run on a device, your CPU steps through each operation and invokes them sequentially. When something goes wrong, and your program suspends, there are ways to inspect the state the CPU was in when a crash occurred and you can glean information from it. This is a lot less difficult than you might think.  For more information on this topic, please refer to this excellent post titled “So you crashed in objc_msgSend()“.  I’ll only be giving a high-level overview, so I highly suggest you read and bookmark that link.

Consider the sample that that above post tries to cover: your application has crashed in the objc_msgSend() method, which is Objective-C’s low-level method invocation function.  When this happens you usually don’t have any information to go on, other than a cryptic exception titled EXC_BAD_ACCESS, with your breakpoint pointing at your main.m file.

By printing the value of the CPU registers in the debugger console you can extract information about what method was being invoked.  Typing “x/s $ecx” for the iOS Simulator, or “x/s $r1” for an iOS device, will print the name of the selector that was being run that resulted in a crash.  It’s that simple!

Perhaps even more useful is when you encounter situations where you crash at objc_exception_send but it doesn’t give you the reason for the exception. Simply drop into GDB and type “po $eax” for the simulator, or “po $r0” for the device, to print out the message of the exception.

Defensive coding

Above all else some of your best debugging techniques will be to avoid crashes altogether. Practice defensive coding by using some common C and Objective-C patterns. Don’t retain delegates, release your ivars in dealloc or in viewDidUnload. And when you release an ivar, also set its value to nil.  In fact I go so far as to create a macro that handles that for me.

#define DNRelease(x) [x release], x = nil

A technique referred to as “Yoda-Conditions” means for you to reverse your conditionals so that constants are placed on the left-hand side of your operator.  For example:

if (YES == someBoolean) ...

That is much less intuitive since nobody but Yoda speaks in reverse like that, but what this does buy you is compile-time protection against accidentally assigning a value instead of comparing it.  A simple “if (someBoolean = YES)” statement can be time-consuming to track down and is easily avoided if you always write your comparisons the other way around.

And above all else make sure you write readable code. Nobody likes ugly code, but for more than pure aesthetics. Ugly or confusing code can hide more bugs, and when you use good whitespace, sensible variable names, and you structure your code cleanly, you can expose bugs earlier and make them easier to track down later.

Good luck and happy bug-hunting, and I hope this starts you off on the right foot!

Core Graphics isn’t scary, honest!

$
0
0

For anyone who’s developed exclusively with UIViews on iOS may take the title of this post a bit oddly. “WHAT?!” they might say, “Are you insane? Core Graphics is not only a C-only API, but has confusing function names, and needs way more code to do the same thing I can do in less code in UIView”.  Yes, they might be right, but there’s a reason why Core Graphics exists. It’s FAST!

But using Core Graphics doesn’t mean that your code has to be confusing, or that you have to compromise flexibility for performance. You can have your cake and eat it too (aka you can have high-performing code that is easy to read). Read on to see what I mean.

Baby steps in using drawRect:

The drawRect: method is your entry point to drawing in Core Graphics, and is (for the most part) the only place where drawing operations can be performed. This is the biggest problem newbies have when getting started with low-level drawing on iOS because they’re used to being able to add subViews or subLayers arbitrarily in whatever method they happen to be in.

drawRect: is called by the underlying graphics subsystem in its main frame rendering loop.  When it’s time to draw the next frame, iOS digs through all the views on the screen and checks to see if its content needs to be updated. If it does, then your drawRect: method is called with the appropriate rect that needs to be updated.  It’s as simple as that.  You get asked to draw your content when, and only when, it needs something from you.

Finding your context

All drawing operations in Core Graphics utilize a context pointer to keep track of what region your drawing operations will be made to. This is a standard thing you’ll find in C APIs because without an Object-Oriented “self” property easily available, you have to provide some means of providing context.

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // Do something with your context
}

From that point on you can use the “ctx” variable for all subsequent Core Graphics calls.

Saving state

If you want to draw anything on the screen, even if it’s something as simple as a single line, you’ll need to use several function calls to do so. This is because separate calls are used to set attributes such as the line colour, the line width, any end-cap settings you may want for the corners of your line, and then the actual path that your line will follow.  Core Graphics keeps track of all these different attributes by updating its internal state.

Think of the drawing state as a pen: you change the tip, you change the colour, and then you can draw many separate lines with the same pen.  But if you forget to change your pen back, you can mess future drawing calls up if you don’t clean up after yourself.

To work around problems like this it’s best to use the CGContextSaveGState and CGContextRestoreGState functions.  Think of it as saving a bookmark or a checkpoint of your current graphics state.  You can then change any drawing attributes you like, you can draw or fill or stroke any path, and when you’re done you reset the graphics state back to what it was before.

There is one important catch however: the number of times you call Save and Restore must match perfectly, because otherwise you may screw up the drawing state for whomever is calling your class. This is important because otherwise some really weird garbage may end up getting drawn to your screen.  To get around this, I use a very simple technique that I’ll show in the code sample below.

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSaveGState(ctx);
    {
        // Draw whatever you like
    }
    CGContextRestoreGState(ctx);
}

By including a new set of brackets in your code, you give yourself a visual indentation of code that is covered by a set of save and restore calls.

Simple drawing using UIView classes

There are some fairly simple operations that some people want to do that are made easy by a few simple helper methods provided in a few UIView subclasses. For example, assume you’re building the next greatest Twitter application and you want to squeeze as much performance out of your feed items as you possibly can.  Obviously rendering text, images, gradients, borders and shadows are fairly expensive operations if you want to handle scrolling through thousands of feed posts at 60fps.

Fortunately you don’t have to replace your UIView classes with hundreds of lines of Core Graphics calls. Many of the most common classes like UIImage, UIBezierPath and so on, all provide convenience methods for drawing their content within drawRect: using Core Graphics directly.

Update: The original post had a few bugs in it, mostly due to writing this post exclusively from memory during the Christmas holidays. As a result of some very helpful comments on this post however, I’ve had to make some changes. I apologize for the bugs in the first version.

UIImage drawing

We can use UIImage objects to directly draw to a Core Graphics context. Using raw API calls makes for very verbose code, since you’d have to create a CGImage object, a color-space object, and so forth. Instead, drawing an image can be as easy as the following.

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    UIImage *img = [UIImage imageNamed:@"MyImage.png"];
    [img drawInRect:rect];
}

With this technique you have many more options, such as blending and alpha arguments. There are other methods that let you draw an image at a particular point, drawing a pattern, and so forth.

UIBezierPath drawing

Often times you might want to show rounded corners on some view, but you only want certain corners to be rounded. For example lets assume you want to show a container view with only the top two corners rounded. The most straight-forward strategy is to drop into Core Graphics to render. While it’s possible to compose a path using low-level APIs alone, it’s quite simple to do the following.

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextSetLineWidth(ctx, 3);

    UIBezierPath *path;
    path = [UIBezierPath bezierPathWithRoundedRect:rect
                                 byRoundingCorners:(UIRectCornerTopLeft |
                                                    UIRectCornerTopRight)
                                       cornerRadii:10.0];
    [path stroke];
}

Responding to user input

Core Graphics tries to be as efficient as possible, and so it takes some shortcuts on your behalf. For the most part these are exactly what you want and would expect, and come as a pleasant surprise when you come from other platforms. But there are times that it can get in your way, so knowing in advance what those optimizations are and how to control them helps. And knowing is half the battle…

Knowing when your view “Needs Display”

Your drawRect: method will only be invoked when UIKit feels your content has become stale and needs to be redrawn. For the most part this typically means your drawRect: method will be called when the view is added to a superview. Since drawRect is called when the frame is drawn, calling it explicitly won’t work as you’d expect, so if some user interaction requires you to redraw your content, there’s a simple solution for that.

All UIView objects have a method called “setNeedsDisplay“. Invoking this will toggle a flag inside your object indicating that your view needs to be redrawn upon the next frame. This has several advantages, including the fact that it makes your code very quick; this is because no matter how many times you call it within the same runloop, your frame will still only be redrawn once on the next frame. Therefore you don’t have to worry about over-invoking it, ensuring that you can keep your content fresh from wherever your UI logic determine content needs to change.

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        CGRect labelRect = CGRectMake(32, CGRectGetHeight(frame) - 32, CGRectGetWidth(frame), 32);
        self.likeLabel = [[[UILabel alloc] initWithFrame:labelRect] autorelease];
        self.likeLabel.font = [UIFont systemFontWithSize:12.0];
        self.likeLabel.autoresizingMask = (UIViewAutoresizingFlexibleTopMargin |
                                           UIViewAutoresizingFlexibleRightMargin);
        [self addSubview:self.likeLabel];
        
        self.likeIcon = [UIImage imageNamed:@"likeIcon.png"];
        self.unlikedIcon = [UIImage imageNamed:@"unlikedIcon.png"];
    }
}
 
- (void)dealloc {
    self.likeLabel = nil;
    self.likeIcon = nil;
    self.unlikedIcon = nil;
    [super dealloc];
}
 
- (IBAction)likeClicked:(id)sender {
    // Update the label's text
    self.isLiked = !self.isLiked;
    self.likeLabel.text = (self.isLiked) ? @"Liked by you" : @"";
 
    [self setNeedsDisplay];
}
 
- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // Determine the coordinates we want our content drawn at
    CGPoint iconPoint = CGPointMake(floorf(self.likeIcon.size.width / 2),
                                    CGRectGetMidY(self.textLabel.frame));
    
    // Draw the content
    UIImage *image = (self.isLiked) ? self.likedIcon : self.unlikedIcon;
    [image drawAtPoint:iconPoint];
}

In the code example above you’ll notice that we’re creating the UIImage object in initWithFrame:, and are destroying it in dealloc, so that we don’t have to allocate objects within the drawRect: method. It’s important to keep that method as quick as possible so you don’t negatively impact your screen’s framerate.

Responding to frame size changes

When your view changes its size, either when explicitly set or when a superview autoresizes its subviews, your content will be invalidated in some way. But rather than calling expensive drawRect: methods all the time when this happens, UIView objects have a contentMode property that lets you give UIKit a hint about what you want it to do in this situation.

This property is an typedef enum named UIViewContentMode and has a bunch of different options that you should check out. The default value is UIViewContentModeScaleToFill which means if your frame’s size changes, UIKit will simply take the last-rendered result your drawRect: method created and will scale it up or down to fill the available space.

The simplest way to get your content to redraw is to set your view’s contentMode to UIViewContentModeRedraw, but in many cases this may be overkill.

For example, lets assume your drawRect: method draws a border and some comments along the bottom of your frame, as the “Like” example does in the previous section. If your frame changes its height it would be wasteful to perform a full redrawing operation when most of the content hasn’t changed. So if you set the contentMode to UIViewContentModeBottomLeft UIKit will align the content in the bottom-left corner of the view, cropping the rest of the content as it does so.

Avoid drawing across pixel boundaries

When you position elements on the screen (not just with Core Graphics, but in UIKit in general) you need to make sure that your views exist at integer pixel coordinates. iOS’ drawing coordinate system works in points, not absolute pixels, which means it’s possible to tell UIKit or Core Graphics to draw content at a fractional-pixel. Since this is impossible, the device attempts to anti-alias your content so that it blurs between several pixels. This is almost never what you want, so when calculating positions (especially when dividing one value by another) it’s important to use the floorf or ceilf functions to round the values down or up to the nearest integer.

This is more obvious when drawing or stroking lines or paths on the screen. Lets take the following example where we draw a single line along the bottom of the view. For this example however we’ll use the low-level drawing routines to compose a path, instead of using a UIBezierPath object.

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextSetLineWidth(ctx, 1);
    
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, 0, CGRectGetMaxY(rect));
    CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
    CGContextStrokePath(ctx);
}

This code seems pretty straightforward; move the drawing “pen” position to the bottom-left corner, add a line to the bottom-right corner, and stroke the resulting path with the line width and line color previously defined.

The “gotcha” here is that when you create a point at (0, 0), that represents the logical upper-left corner of the screen. However the pixel in the top-left corner occupies the space defined by the frame (0, 0, 1, 1) (e.g. a 1-point square starting at (0, 0)). When you draw a line it is centred on whatever coordinates you give it. Therefore in the code example above, your code is asking Core Graphics to draw a line that has 0.5 in one pixel, and 0.5 in another pixel.

To get around this you should offset your drawing frame so that you draw 0.5 points offset. Here’s an updated version of that code which draws a solid unblurred line:

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextSetLineWidth(ctx, 1);
    
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, 0, CGRectGetMaxY(rect)) - 0.5;
    CGContextAddLineToPoint(ctx, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
    CGContextStrokePath(ctx);
}

Drawing with colour the easy way

Core Graphics has evolved over time, with new and improved APIs. This means that for many drawing operations there might be several different function calls that will give you the same result. This is especially true when dealing with colour.

For example, if you want to set the stroke (aka “line”) colour in Core Graphics, there are four separate function calls that will achieve the same result. Your impulse might be to pick the first result that comes up, but that means more work for yourself. The standard CGContextSetStrokeColor function call takes an array of CGFloats indicating the different colour values you want to draw with.

However there’s a much easier way. CGContextSetStrokeColorWithColor is a slightly more verbose function name, but allows you to supply a CGColorRef value to describe a colour. And as a convenience, the UIColor class provides a helper property called CGColor that returns a pre-calculated colour reference, which automatically releases its memory when the UIColor object goes away. This means you don’t need to manually malloc or release your colour references, and results in much less code.

You can see some of the code examples up above where I’ve already used this function and property. Whenever you see a function that has a “ColorWithColor” option, it uses this pattern.

Use the right tool for the job

Perhaps the best advice I can give is to use the right tool for the job.  For example, if you need to visually style some interface element, you shouldn’t add unnecessary subviews just to draw things like borders, rounded corners, tiled patterns, and so on.  Additionally there are cases where having a large number of subviews (such as in UITableViewCells) is inefficient and rendering simple elements like icons, text, or borders is better suited to Core Graphics.

iOS and UIKit is really a different environment than HTML, and you can’t treat device layout and rendering the same way.

And finally, make sure you practice, and don’t be afraid of trying out Core Graphics.  Start simple with things like borders, rendering images and text, or programmatically rendering effects that would otherwise be slow using Core Animation or image-based textures.

Announcing Docset Viewer v1.1 for iPad and iPhone

$
0
0

Over the years my blog has transformed from the usual “Wordy geek ranting about first-world problems” content toward more educational and informative posts on what I do for a living: developing awesome iOS applications. I don’t usually talk about the actual applications I’m writing though, since most of my work is on other people’s apps (and I’m not allowed to spill the beans on anything fun). I still consider myself an “Indie” developer though, and just like many other developers out there, I like to solve the problems that I myself face on a daily basis.

In this case what started with me complaining on Twitter turned into a new app due to the resounding and immediate “Me too!” responses I got from some of my followers. And with that I decided to create Docset Viewer.

One of my problems has constantly been related to reading developer documentation in Xcode. When your computer’s overloaded, Docsets take forever to load in Xcode. And when I’m on the go, or am just working from my laptop’s tiny screen, having to switch back and forth between my code view and documentation view is tedious. My only other option is to open up the docs on my iPad, but that doesn’t work when I’m travelling (and don’t have 3G access) or when I’m on a plane. And finally once you do get the documentation onto the iPad it’s horribly slow because of the HTML5 custom UI that Apple redirects you to when you’re accessing their docs from an iPad.

All I wanted was to quickly browse and search documentation from a screen I know I’ll already have next to me, without needing Internet access or an external monitor, that works even when my computer is being buried under Xcode’s bloated load.

The first version of Docset Viewer, v1.0, was very simple and had some limitations I wasn’t too happy with.  This is why, with v1.1, I’ve added the following features:

  • Download Docsets online or using WebDAV.  You can download from one of Apple’s pre-defined Atom feeds, or you can point the app at any Docset atom feed you like to download additional content like Cocos2D documentation.
  • Now a Universal app, supporting both the iPhone and iPad.
  • Caching of compressed files for quicker access while keeping disk usage low.  Instead of extracting the compressed contents, taking up more space on disk, Docset Viewer reads the compressed contents directly.
  • Supports “XAR” and Zip archives, as well as standard .docset package directories
  • New info pane to show details of a Docset, number of documents, space used, etc.
  • Search through the contents of a Docset for quick access, either by API name or by document title.
  • Full-screen support.

In keeping with the instructional nature of my site, I’m going to show you a few things that I did in Docset Viewer and how I put it together. Hopefully that will show you how easy it is to take “Off-the-shelf parts” and combine them with Apple’s awesome UIKit framework to create easy-to-build Universal applications.

Over the next few days I’ll be covering the following topics:

  • Resuming large downloads with NSURLConnection
  • Simplifying development with category extensions
  • Using UIKit the way it was intended

If you’d like to give the app a try, hop over to the App Store and check it out.

Update: It’s been brought to my attention that people seem to think I ripped off a competing app’s codebase.  I want to state for the record that nothing of the sort happened.  In fact my app’s v1.0 release dates back to January (submitted to the App Store on January 19th to be precise), before the competing app was released.  I didn’t announce the app back then because it didn’t have all the features I wanted, namely being able to search or download Docsets from Atom feeds; that original v1.0 version required Docsets to be transferred using iTunes document sharing.  I feel that competition is healthy, and since I’m very proud of this release, I feel there’s certainly room in the market for any apps.

Since I already have planned to showcase certain pieces of my code that I’m proud of, I hope people will see that my app is not similar to my competitor’s at all.

Docset Viewer: Resuming large downloads with NSURLConnection

$
0
0

As I’ve shown in my previous post announcing Docset Viewer, I want this series of posts to be more than me talking about my new app. In keeping with the instructional nature of my site, I’m going to show you a few things that I did in my new app Docset Viewer and how I put it together. This time around I’m going to show how I use NSURLConnection for downloading large files, and even resuming them.

In Docset Viewer I’ve added the ability to download docsets directly from Atom feeds, either from custom URLs or from a pre-configured list of Apple’s available docsets. Since you may not be consistently connected to the Internet, it’s important to be able to download documentation packages incrementally, especially since they can be anywhere from 300MB to 500MB.

Resuming large downloads with NSURLConnection

Apple’s NSURLConnection class is extremely easy to use, especially when you want to perform a simple network request.  Customizing a request involves a little bit more work, but it needn’t be complicated.  You begin by creating an NSMutableURLRequest object and checking to see if the request can be made.

NSMutableURLRequest *req;
req = [NSMutableURLRequest requestWithURL:docset.feedModel.downloadURL
                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                          timeoutInterval:30.0];
if (![NSURLConnection canHandleRequest:req]) {
    // Handle the error
}

In order to resume a network download, you need to know where your download left off.  For that we need to check how many bytes we’ve downloaded so far, if any.

// Check to see if the download is in progress
NSUInteger downloadedBytes = 0;
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:docset.downloadPath]) {
    NSError *error = nil;
    NSDictionary *fileDictionary = [fm attributesOfItemAtPath:docset.downloadPath
                                                        error:&error];
    if (!error && fileDictionary)
        downloadedBytes = [fileDictionary fileSize];
} else {
    [fm createFileAtPath:docset.downloadPath contents:nil attributes:nil];
}

The code above checks if the download’s temporary file exists and checks its file length. If the file doesn’t exist, we create it so there’s a file for us to append to. From here now all we have to do is check to see if we need to resume a download, or start the download from scratch.

if (downloadedBytes > 0) {
    NSString *requestRange = [NSString stringWithFormat:@"bytes=%d-", downloadedBytes];
    [req setValue:requestRange forHTTPHeaderField:@"Range"];
}

The above code sets the HTTP-Range header, indicating which byte-range we want to download. By specifying a “XXX-” range, with a trailing dash, this tells the server that we want to download to the end of the file, starting from the indicated byte offset.

There are a few additional goals I had. In addition to downloading the content I wanted to make sure that very little memory was used, so I needed to save the file to disk as it’s downloaded. I also wanted to be able to cancel the download at any point. NSURLConnection has several different modes it can function in, so in this case I did the following:

NSURLConnection *conn = nil;
conn = [NSURLConnection connectionWithRequest:req delegate:self];
self.downloadingConnection = conn;
[conn start];

From this point forward the connection will begin downloading. Your class needs to implement the NSURLConnectionDataDelegate and NSURLConnectionDelegate protocols. The first protocol defines a set of methods that notifies you whenever a buffer of data is received from the connection. The second protocol defines methods that inform you when the network connection starts, when it fails, and when it completes. Lets go through each of these delegate methods one by one.

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    self.downloadingConnection = nil;
    // Show an alert for the error
}

That’s the easy one, but what we really care about is finding out from the server whether or not it was able to honour the HTTP-Range header so we know if we have to wipe our temporary file clean and start over again.

- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
    if (![httpResponse isKindOfClass:[NSHTTPURLResponse class]]) {
        // I don't know what kind of request this is!
        return;
    }
  
    DocsetFeedModel *docset = self.downloadingDocset;
    NSFileHandle *fh = [NSFileHandle fileHandleForWritingAtPath:docset.downloadPath];
    self.fileHandle = fh;
    switch (httpResponse.statusCode) {
        case 206: {
            NSString *range = [httpResponse.allHeaderFields valueForKey:@"Content-Range"];
            NSError *error = nil;
            NSRegularExpression *regex = nil;

            // Check to see if the server returned a valid byte-range
            regex = [NSRegularExpression regularExpressionWithPattern:@"bytes (\\d+)-\\d+/\\d+"
                                                              options:NSRegularExpressionCaseInsensitive
                                                                error:&error];
            if (error) {
                [fh truncateFileAtOffset:0];
                break;
            }
  
            // If the regex didn't match the number of bytes, start the download from the beginning
            NSTextCheckingResult *match = [regex firstMatchInString:range
                                                            options:NSMatchingAnchored
                                                              range:NSMakeRange(0, range.length)];
            if (match.numberOfRanges < 2) {
                [fh truncateFileAtOffset:0];
                break;
            }
  
            // Extract the byte offset the server reported to us, and truncate our
            // file if it is starting us at "0".  Otherwise, seek our file to the
            // appropriate offset.
            NSString *byteStr = [range substringWithRange:[match rangeAtIndex:1]];
            NSInteger bytes = [byteStr integerValue];
            if (bytes <= 0) {
                [fh truncateFileAtOffset:0];
                break;
            } else {
                [fh seekToFileOffset:bytes];
            }
            break;
        }
  
        default:
            [fh truncateFileAtOffset:0];
            break;
    }
}

From what you can see above, we expect an HTTP 206 response code from the server when it tells us it’s able to fulfill the HTTP-Range request. But at this point I don’t want to blindly trust the server, so I inspect the HTTP headers and parse out the byte range it’s sending me to verify where the byte range begins. If all goes well we can seek our file handle to the appropriate byte offset, and we can resume the file from where we left off.

There are undoubtedly some bugs in here where, for example, the server returns the proper range response but perhaps the server malformed the header, meaning we’re storing corrupted content. But in that event simply deleting the file and starting over is probably an acceptable option.

Our next step is storing the data as it’s downloaded.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.downloadingFileHandle writeData:data];
    [self.downloadingFileHandle synchronizeFile];
}

And finally closing the file when the download is complete.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    DocsetFeedModel *docset = self.downloadingDocset;
  
    [self.downloadingFileHandle closeFile];
    self.downloadingFileHandle = nil;
    self.downloadingConnection = nil;
    self.downloadingDocset = nil;
  
    NSFileManager *fm = [NSFileManager defaultManager];
    NSError *error = nil;
    if (![fm removeItemAtPath:docset.rootPath error:&error]) {
        // Show an error to the user
    }
    if (![fm moveItemAtPath:docset.downloadPath toPath:docset.rootPath error:&error]) {
        // Show an error to the user
    }
}

From this point the rest is yours. You can track your download progress like I do by sending NSNotificationCenter messages when convenient chunks of data are downloaded (I don’t post those messages on every connection:didReceiveData: message so I don’t overload the main thread with notifications), you can pause and resume downloads, and can do even more.

Once you begin working with NSURLConnection you can efficiently transfer as much data as you want, and can even play with multiple-range requests if you want to get really fancy.

Good luck, and if you want to check this out in action (and support my app at the same time), try out Docset Viewer on the iTunes App Store.

Docset Viewer v1.2 and how to customize iCloud backups

$
0
0

I’ve recently released version 1.2 of Docset Viewer, which fixes a number of bugs people experienced with the previous version. If you had problems with the previous release, please give this one a try.

One of the improvements I’ve added is the ability to customize whether or not you would like to back up your Docsets (which can get quite large) into iCloud. To keep with the instructional nature of this site, I’ll show you how you can do that in your own apps.

MobileMe/iCloud backup basics

iCloud replaces the former MobileMe backup mechanism for syncing files for backup.  In both MobileMe and iCloud, you use the -[NSURL setResourceValue:forKey:error:] method to set a boolean attribute indicating whether or not an individual file should be excluded from backups.  By default all files will be backed up.

In Docset Viewer, since the files can take up hundreds of megabytes, all of which are often times easily downloaded from the Internet, it doesn’t make sense to back them all up and use all your precious iCloud capacity.

The only problem is that the new iCloud backup resource value was introduced in iOS 5.1, and replaces the former MobileMe tag.  Furthermore you get an error thrown when you attempt to set the old MobileMe resource tag.  So what’s a developer to do when you need to support multiple versions of iOS?

Sample code for configuring backup options

NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:rootPath];
NSString *fileName = nil;
NSNumber *backupValue = [NSNumber numberWithBool:YES];
while ((fileName = [enumerator nextObject])) {
    NSURL *fileURL = [NSURL fileURLWithPath:[rootPath stringByAppendingPathComponent:fileName]];
  
#if __IPHONE_5_1
    if (&NSURLIsExcludedFromBackupKey != nil) { // iOS >= 5.1
        [fileURL setResourceValue:backupValue forKey:NSURLIsExcludedFromBackupKey error:&error];
        if (error)
            NSLog(@"Error setting iCloud Backup value to %@ for %@: %@", backupValue, fileName, error);
    } else
#endif
    {
        [fileURL setResourceValue:backupValue forKey:@"com.apple.MobileBackup" error:&error];
        if (error)
            NSLog(@"Error setting MobileBackup value to %@ for %@: %@", backupValue, fileName, error);
    }
}

Let me walk you through this code step-by-step.

First we fetch a directory enumerator so we can step through each file within the path that we want to configure. Each file has to be individually configured to be excluded from backups, so this is an efficient way to step through your files.

The next step, within the enumerator loop, is to fetch a file URL for the file on the local device that we want to configure.

From here the code gets a little trickier. We determine if the current device supports the iCloud backup key by checking if the NSURLIsExcludedFromBackupKey constant is defined. If this source code is compiled on Xcode 4.3, but the compiled code is running on iOS 5.0 or below, then the value for that constant will be nil, allowing us to fall back to the “else” block. However, to be on the safe side, I added a conditional compiler directive to only compile the snippet of code supporting iCloud if this source is compiled on an older version of Xcode. Over time this will become less important, but if you’re using Xcode 4.2.x or below, then the NSURLIsExcludedFromBackupKey constant won’t be defined and referencing it would be a compile-time exception.

Note: Normally you wouldn’t want to rely on using compile-time directives in your project because the compiled output of your application can run in a number of different environments, so performing run-time checks is crucial (like we’re doing here with the if/else code). The only reason we’re using this here is for circumstances where this code is compiled on an older Xcode.

Finally, in the else block, we fall back to setting the old “MobileMe” backup key.

Finishing touches

Before diving in and using this, you might want to consider how many files you’re setting backup exclusion options for, whether or not those files really should be backed up, or when you perform these updates. If you have a large number of files you may want to consider running this in an asynchronous block call, or even run it across several different blocks so you don’t block a single CPU core unnecessarily (especially on the iPad 1 or iPhone 4 where those devices only have a single-core CPU).

Additionally, if you’re setting this value to content that is able to be re-generated, or on cache or temp data, you should consider storing your local files in a different directories more suited to those tasks. Some directories (such as the Library/Caches or temporary directories) aren’t ever backed up, and are the preferred location for storing that data.

Good luck, and if you want to check this out in action (and support my app at the same time), try out Docset Viewer on the iTunes App Store.


Logging with CocoaLumberjack and TestFlight

$
0
0

Consider the following situation that happens far too often in mobile app development: You’ve just released an app that works perfectly for you, and you’ve tested it extensively. You’re proud of your accomplishments and submit the app to the world, only to have several emails sent to you from users who have nothing but difficulties in running the app. You send a bug fix release to the App Store, but since you’re still unable to reproduce the problem you’re at the whim of luck and end-user feedback. You can hope your users know how to send you a crash report, but what if the app isn’t actually crashing? Wouldn’t it be great to be able to access your app’s log information from that client to be able to troubleshoot the problems?

In working on Docset Viewer I’ve run up against this very same problem. I’ve solved most of the bugs reported to me, but I still have gotten a few troubling reports that users have gotten into a stuck state where they had to uninstall/reinstall the app to get it to work consistently. Obviously some bad data got stored somewhere that was breaking the app, but until I’m able to find out what it was that was making the app feel ill, I can’t solve the root cause.

With the recent release of TestFlight’s “Live” service, they allow for automatic crash-log reporting and log-file upload support to their cloud-based service. But since the vast majority of my users don’t have any problems using my app, I don’t want to wade through tons of log information. Additionally, during the development of the app I’ll use console logging for my own internal diagnostics, but the high level of verbosity would be overkill when used in a production app. Instead of simply commenting out or deleting log lines when I’m done developing a feature, it would be useful to have a flexible logging solution that would let me develop my code with ease, while still allowing to have certain high-priority log messages make it through to me in production.

I’ve managed to come to a happy medium between ease of use and cloud-based log reporting by combining the excellent CocoaLumberjack library with the TestFlight Live SDK.

What’s TestFlight Live

TestFlight has been around for a while as a solution for simplifying the beta-tester management process.  It includes an SDK that lets you send crash reports and usage information to the web-based service to see which beta testers have installed the app, what issues they’ve encountered, and even provides a method to send feedback to you from within the app.  Recently however they released an update to their service that extends it to become TestFlight Live, which provides crash log reporting and usage analysis for live apps in the App Store.

What’s CocoaLumberjack?

In it’s own words, CocoaLumberjack is “…similar in concept to other popular logging frameworks such as log4j, yet is designed specifically for Objective-C, and takes advantage of features such as multi-threading, grand central dispatch (if available), lockless atomic operations, and the dynamic nature of the Objective-C runtime.” It is faster than plain NSLog, is more flexible through the use of different log levels, and is pluggable for providing additional modes of logging above and beyond simple console logging.

I was introduced to this wonderful framework through the CocoaHTTPServer library which I use in Docset Viewer as well as another upcoming app of mine.  In my apps so far however, I took many of Lumberjack’s more advanced features for granted, only opting to use its different log-levels and per-configuration log targets to customize my app’s behaviour.  For example, on debug builds my app logs at a higher verbosity than on release builds.

This all changed when I released my recent v1.3 update to Docset Viewer.  Between v1.1 and v1.3 I fixed a number of bugs reported by my users, and the app is far more stable as a result. But there are still some hard-to-reproduce issues that are occurring and I need more information to be able to correct them properly.

To get more insights into what’s happening, I used Lumberjack’s custom logger capability to add my own class for reporting log messages to TestFlight.

#import <UIKit/UIKit.h>
#import "DDLog.h"

@interface TestflightLogger : DDAbstractLogger <DDLogger>

@end

#import "TestflightLogger.h"
#import "TestFlight.h"

@implementation TestflightLogger

- (void)logMessage:(DDLogMessage *)logMessage {
    NSString *logMsg = logMessage->logMsg;
    if (logMsg)
        TFLog(logMsg);
}

@end

Using this in your application is easy. You simply need to add the following lines to the beginning of your application:didFinishLaunchingWithOptions: method:

[TestFlight takeOff:kTestFlightTeamID];
[DDLog addLogger:[DDASLLogger sharedInstance]];

#ifndef DEBUG
    TestflightLogger *logger = [[[TestflightLogger alloc] init] autorelease];
    [DDLog addLogger:logger];
#endif

This assumes you have a “DEBUG” definition declared for your debug or adhoc builds which helps prevent log messages filtering into TestFlight unnecessarily.  With this addition, not only will your TestFlight account give you timely information about crashes encountered by your users, but you’ll have access to the log messages that will provide valuable insights into why those crashes occurred.

This is just the tip of the iceberg, and I’m sure there’s more areas where TestFlight and Lumberjack can be used to enhance your ability to quickly fix bugs.

My App Store release checklist

$
0
0

For the longest time it seemed that releasing an update to an iOS app was a random whack-a-mole process that I’d invariably get wrong in some way.  It was maddening, especially since iTunes Connect has only recently become a decent web application.  By switching to Jenkins for continuous integration of my iOS app builds I’ve greatly improved my process, but things didn’t really improve until I created a checklist for keeping track of my releases.

Since I’ve been asked many times about this very topic recently – both at work and on Twitter – I thought I’d write a post about how I bring some sanity to my release process so my app updates are timely and predictable.

Plan for your release early

Perhaps the best thing you can do to get some consistency in your releases is to plan ahead; if the end-goal of your project is to release an app (which, lets face it, really should be the case) then you should treat your release artifacts as if they were as important as your code.  The sorts of things that make up your release are:

  • App Store description text
  • App Store keywords
  • App Store update text
  • Screenshots for both iPad and iPhone/iPod Touch
  • 512px app icon
  • App binary IPA

Most of those points above don’t involve any code, yet constitutes a great deal of effort on your part. Getting your screenshots refined so you show the most compelling parts of your app, refining your description to showcase your app the best way possible, and tweaking the “updates” text so you can quickly convince your user that they should update to the latest version.  Those are all important steps to refine, and if you don’t have an easy way of editing and versioning that information then you’re already running behind.  These aren’t steps you should rush at the end of a release period, so take your time and do it right.

The root of my Github projects always contain the following two subdirectories: “src” which contains my Xcode project, and “AppStore” which contains all the assets required to roll out a release.  As you can see from the attached screenshot, I include separate files for my app description, keywords, etc.  This is also a great place to store any promo codes you’ve downloaded from the App Store, screenshots of your app, etc.

Localize early

As you can see from the screenshot, you can tell that I’ve translated Docset Viewer into French, Spanish and Chinese. I use the great iCanLocalize.com service for translating the strings embedded in my app.  When I’m getting close to a release I generate my new localizable strings files, send them off to iCanLocalize, and wait for them to be translated.  At this time I also send off my Description.txt, Updates.txt and Keywords.txt (if it has changed).  This makes sure that people in those locales can properly read my app store description page, and makes it more likely for them to buy and install my app.

An important step that many people forget is to localize your app screenshots as well.  As you can see in the screenshot, I have separate subfolders in my “Screenshots” folder for each language I support.  Not only do you have to take screenshots of your app in English, but you should take those very same screenshots in each supported language.

I typically use the iOS Simulator for my screenshots and use the “Copy Screen (^⌘C)” shortcut which takes a screenshot and places it in your clipboard.  I then paste each screenshot individually into its own layer on a Photoshop document, from which I can save all layers as separate images, making the process of exporting my screenshots a bit simpler.

Create a test plan

It may seem like overkill for some small apps, but regardless of the size of your app, you should create a test plan.  This can be as simple as a bulleted text document that lists out the various scenarios you should test.  For example, mine contains entries like the following:

  • Suspend the app in the middle of a download
  • Start a download when another is already in progress
  • Delete a docset bundle that is currently being viewed on an AppleTV over AirPlay
  • Switch from 3G to Wifi or Airplane Mode while viewing documentation
  • Search for empty whitespace on a 1st-gen iPad

And so forth. Essentially any circumstance I’ve ever run up against that has crashed my app during the course of development I re-test manually before releasing my app.  I’ll prioritize the list based on recently-added or -changed features, but I’ll still run through the list at least once before uploading a release. This is a good thing to do while you’re waiting for your localizations to be finished.

Manage your Jenkins builds

It goes without saying that you should be using some sort of continuous integration on your project to generate your builds and to monitor the quality of your apps over time. If you aren’t convinced, check out my very first blog post on automating iOS app builds since it’s still very relevant today.  But at a minimum you should make sure your build script archives the dSYM files for your finished build in Jenkins so that you’ll be able to properly symbolicate crash logs sent to you from your users (if you’re so lucky).  Without it you’ll be flying blind when trying to read a crash log.

Additionally, when you decide on a particular build that will become your released app, you should mark the build in Jenkins with the appropriate version number, and mark the build as “Keep this build forever”. This will ensure you always have access to your old builds in the event you need to perform upgrade testing from old versions, or to track down bugs in older versions of your app. You’ll notice in the screenshot of my build history for Docset Viewer, instead of showing the build number it shows the app version number, as well as a “lock” icon indicating that those builds will never be accidentally deleted.

Release Checklist

Finally, here’s the full checklist I use to make sure I release my apps consistently, and with quality.  It’s always changing, and sometimes I skip steps if they aren’t needed, but I use it as a guide to make sure I’m on-track and don’t forget any steps.  Good luck!

After Feature-Complete:

  1. Revise Description.txt and Updates.txt;
  2. Generate localization strings (Localizable.strings, InfoPlist.strings, Root~iphone.strings, Root~ipad.strings);
  3. Send localizations to iCanLocalize;
  4. Perform manual test cases (on different generations of device) & get beta-tester feedback;
  5. Take new screenshots in English (if necessary);
  6. Register a new version in iTunes Connect; update description, updates text, screenshots, app icon as needed.

After localizations are complete:

  1. Download & update localizations;
  2. Take new screenshots in each language (if necessary);
  3. Sanity-check the app in each language to ensure labels fit;
  4. Update localizations in iTunes Connect; new updates text, description, and screenshots as needed;
  5. Upload new app IPA to iTunes Connect;
  6. Mark the build in Jenkins as v1.xRC (Release Candidate).

After app accepted by iTunes Connect:

  1. Mark the build in Jenkins as “v1.x” and lock the build so it can’t be deleted;
  2. Checkout that revision in git and tag it with the appropriate release version number;
  3. Go out for a pint to celebrate!

Docset Viewer update v1.5

$
0
0

The past year has been quite a ride, to say the least! I have been so busy with work, creating awesome features and technologies on iOS apps that over a year has raced by without an update to my blog!

I’ve also been neglecting my own apps due to being so overwhelmed with the requirements of my work as the lead developer for Salesforce.com’s iOS Chatter app, so it wasn’t until recently that I updated Docset Viewer to add support for iOS 7.  I’ve adapted the design to fit more in line with iOS7, while still providing the same experience as before on iOS6 and earlier.

In addition to iOS 7, I’ve added support for full-screen mode in landscape on iPad, hiding the sidebar.  I also added search term highlighting in search results to make it easier to find the matching text you’re looking for.

iOS7 and OSX 10.9 Docsets

Normally whenever a new release of iOS or OSX comes out, I add support for downloading the documentation for it right within the app.  This is done using an Atom feed which contains information about the version, size, and URL of the compressed documentation archive.

Starting with iOS7 and OSX 10.9, Apple is restricting access to this Atom feed to allow only Xcode access.  You can try it yourself, try and fetch the following URL using your browser or the command-line:  http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone7.0.atom

Compare that with the previous iPhone6.0 URL, and you’ll see that they’re trying to force users into using Xcode’s new documentation browser instead of allowing 3rd-party access.

Manually adding docset

It’s still possible to add the iOS 7 and OSX 10.9 documentation to your iPad though.  You simply download the documentation with Xcode, zip the docset directory, and drag it into Docset Viewer from within iTunes or using WebDAV.

In Finder, click Go -> Go to Folder (⇧⌘G) and open the folder:

~/Library/Developer/Shared/Documentation/DocSets

Select the documentation directory that ends in “.docset” that you want to add to your device and create a zip file from it.  Once the zip file is finished being created, you can add that to your device using iTunes or by following the instructions in the app to transfer the file using WebDAV.

I’m going to continue finding a solution to work around Apple’s restrictions, if I can, to hopefully improve this experience.

Don’t live to work…

$
0
0

Many people have heard the phrase “Don’t live to work; work to live”.  This usually means that the goal of working should be to enable you to live your life, rather than allowing work to consume your life.  Far too many people in the tech industry sacrifice their families, spouses, children, and even their sleep, in order to make it in this industry.

Unless you’re one of my regular readers you may not have noticed, but I haven’t posted consistently in over a year.  This is because the life / work balance is a very tenuous relationship; in my situation, my family takes 1st priority as a rule.  Since my role as the lead developer for Salesforce.com‘s Chatter application for iOS, now named “Salesforce1“, blogging about the work I do took a back seat to actually doing and building things.

In this day of telecommuting, remote teams, distributed work environments and the like, as long as the work gets done, there’s no point in warming a seat and producing CO² to fill up a dreary office.  Here is my current work environment, where I’m composing this very blog post:

Banzai Pipeline Office

Office location: Banzai Pipeline

I’m sitting at the beach on the North Shore of Oahu, in Hawaii. In the waves in front of me, at the Banzai Pipeline surf break at Ehukai Beach Park, is the Billabong Pipe Masters competition.  I have jelly plugs in the ports of my laptop, a keyboard cover, and a plastic case around my MacBook Pro Retina, and free wifi here at the beach (though 4G tethering is also quite effective).  Work doesn’t have to be a chore, nor does work have to be confined to the walls of an office building.

I’ve been in Hawaii for over 3 months now, and have been doing my regular 9-5 job with a view of the ocean.  With the 2 or 3 hour time-difference between Pacific Standard Time (Hawaii doesn’t adjust its clock for daylight savings time), this means I start the work-day when the roosters crow, and I’m finished my work day shortly after lunchtime, giving me plenty of time to hit the beach, or drive down to Haleiwa town in time for Aloha hour at the bar.

So why am I mentioning all this?  Not only do I think it’s freaking awesome, but more to the point, this isn’t a difficult thing to do.  If you’re single, you can do this.  If you have a spouse who also works from home, you can do this.  And even if you don’t like the peace and calm of the Oahu North Shore community, you can do the same thing someplace else near and dear to your heart.

My point of all this is that it’s important to focus on what’s important to you in life. For me it’s my love of my family, my love of the ocean, and my dedication to doing the best damned work of my life.  When I’m happy, migraine-free, and healthy, I do better work.  When I can give 100% focus to my work without the distractions of an office environment, and when I can constantly recharge my creative batteries by hopping into the waves or watching some excellent world-class surfers fight it out in the Van’s Triple Crown competition, or just watching the stars at night, I can do better work.

And you can too!

Forcing a method to run on the main thread

$
0
0

You know how many times, as an iOS developer, you want to ensure some method or delegate call occurs on the main thread?  We do this dance countless times, and while it’s straight-forward enough, it can be a burden sometimes.

In my code, I usually create a private delegate wrapper method for my delegate selectors, so that I don’t sprinkle logic all throughout my classes; there’s a single point of code where my delegates are invoked, meaning I can’t screw it up. These wrapper methods look something like this:

- (void)delegate_willShowViewController:(UIViewController*)controller {
    if ([self.delegate respondsToSelector:@selector(pagedCellController:willShowViewController:)]) {
        [self.delegate pagedCellController:self willShowViewController:controller];
    }
}

This way I have a tidy way of handling defaults in the event the delegate doesn’t adopt the selector, and my code is much simpler.  However, there are many UI-related calls that should be performed on the main thread only.  I have a lot of boilerplate code that handles this, but I wanted an easy way to automate the process.

Without further ado, here’s a C function and C macro that simplifies kicking off any local selector on the main thread, only if the call isn’t already being made on the main thread.

#import <Foundation/Foundation.h>

extern NSInvocation * DNInvocationForCall(id object, SEL selector, ...);

#define FORCE_MAIN_THREAD(...) if (![NSThread isMainThread]) { \
    NSInvocation *inv = DNInvocationForCall(self, _cmd, ##__VA_ARGS__); \
    dispatch_async(dispatch_get_main_queue(), ^{ \
        [inv invoke]; \
    }); \
    return; \
}

#import "Defines.h"

NSInvocation * DNInvocationForCall(id object, SEL selector, ...) {
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[NSMethodSignature methodSignatureForSelector:selector]];
    [inv setTarget:object];
    [inv setSelector:selector];

    va_list arglist;
    va_start(arglist, selector);

    NSInteger nextArgIndex = 2;
    NSObject *arg = nil;
    do {
        arg = va_arg(arglist, NSObject*);
        if (arg && arg != [NSNull null]) {
            [inv setArgument:&arg atIndex:nextArgIndex];
        }

        nextArgIndex++;
    } while (arg != nil);

    va_end(arglist);

    [inv retainArguments];
    return inv;
}

The function crafts an NSInvocation object based on the object, selector, and a valist of arguments supplied to it. The macro wraps this, and only invokes it when not on the main thread. More importantly, the macro has the ability to return from the current method, halting execution on the current thread.  Now, all I’d need to do is change my delegate wrapper to look like the following:

- (void)delegate_willShowViewController:(UIViewController*)controller {
    FORCE_MAIN_THREAD(controller)
    if ([self.delegate respondsToSelector:@selector(pagedCellController:willShowViewController:)]) {
        [self.delegate pagedCellController:self willShowViewController:controller];
    }
}

I hope this helps you.

Viewing all 13 articles
Browse latest View live