Blog Archives

A Cool KVO Trick

A coworker of mine attended the Voices that Matter conference in Boston a couple of weeks ago and shared this idea about KVO observing from Mike Ash during his Defensive Programming talk.  He suggests supplying a static pointer to the context parameter:


static void *p = &p;

[someObj addObserver:self forKeyPath:@"aPath" options:NSKeyValueObservingOptionNew context:p];

// ...

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == p)
    {
        // do stuff
    }
    else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Seems like a lot of magic at first, but by specifying a context every time and using one that’s not only unique to your object but also to the file containing your subclass you can ensure that the message sent to you is actually for you and you avoid potentially stepping on the toes of your super class. Neat stuff! It’s also worth noting that checking the context pointer first is a super-fast way to see if you need to care about the observation method.

Side note: if you’re not subscribed to Mike Ash’s Friday Q&A blog (link above), you definitely should. I learn something new there every week.

Speaking tonight at FWT!

I’ll be speaking tonight at the Frederick Web Technologies meetup at 7pm.

Details are here on meetup.com, and my sample code as been pushed to GitHub.  My slides are currently converting on slideshare, let’s hope I have more luck with them than I’ve had in the past.

I’ll be talking about introductory iOS development and highlighting some sample code.

EDIT: Slides are up!

ARC: Cat’s out of the bag

LLVM has posted about the new automatic reference counting feature coming in (I assume) future versions of the compiler.  I have a hard time thinking of this as a helpful improvement in dealing with memory in objective-c in a non garbage collected environment:

  • It doesn’t change the way you think about your allocations.  You still have to place __weak, __strong, or __autoreleased to tell LLVM how you intend to use the declaration.
  • If you’re already declaring your intentions to the compiler, why not simply go the extra step and follow through.
  • The above also holds for the new @autoreleasepool directive to run a local pool.

I also have a few, more personal reasons for not liking the feature:

  • It makes the code uglier: __weak, __strong are not particularly attractive to look at.
  • Alongside the above, I feel it’s a poor abstraction: In a purely garbage collected environment like java or any scripting language du jour, there’s not even a mental model for memory under the hood with the notable exception of scoping rules.  You can simply “new” an object, and it’s there until you either null it out or it goes out of scope.  In the case of ARC, you still have to have be somewhat aware of what you’re doing, but you don’t necessarily need to REALLY understand what’s going on under the hood in terms of the retain count and balancing retain release calls.  As I see it, a clearer and more complete understanding is better than a foggier one any day.  This brings me to my next point:
  • Understanding and managing your memory makes you a better programmer:  There’s something to be said for the level of detail you must think about while working with the memory model in objective-c, and I can’t help but that it pervades the entire application process from design to testing.
  • Is it really all that hard?  Objective-c provides quite clear ownership rules, and with the reference counting built into NSObject, it’s relatively easy to manage memory properly.  Sure, there are plenty of beginner mistakes to be made both with leaking memory and the dreaded EXEC_BAD_ACCESS crash, but now after writing iOS code for a couple years, typing something like [[NSMutableArray array] retain] feels perfectly natural and automatic.

What are your thoughts on adding ARC to your development workflow?

Jeff LaMarche on the runtime and properties

Some time ago I posted about printing all the properties of an object using the runtime.  I was poking around the NSConference site today and found a talk by Jeff LaMarche on the same topic talking about ways to use the runtime in your application design patterns:

Cocoa Design Patterns that Leverage the Objective-C Runtime (NSConference 2010) from iDeveloper TV on Vimeo.

Objective-C Quickie : Printing all declared properties of an object

Here’s some quick code that will print the values of all declared properties of an object using some of the introspection features of the runtime. This assumes that you’re using the default getter and setter names:


- (NSString *)description
{
    NSMutableString *string = [NSMutableString stringWithString:@""];
    unsigned int propertyCount;
    objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
    
    for (unsigned int i = 0; i < propertyCount; i++)
    {
        NSString *selector = [NSString stringWithCString:property_getName(properties[i]) encoding:NSUTF8StringEncoding] ;
        
        SEL sel = sel_registerName([selector UTF8String]);
        
        const char *attr = property_getAttributes(properties[i]);
        switch (attr[1]) {
            case '@':
                [string appendString:[NSString stringWithFormat:@"%s : %@\n", property_getName(properties[i]), objc_msgSend(self, sel)]];
                break;
            case 'i':
                [string appendString:[NSString stringWithFormat:@"%s : %i\n", property_getName(properties[i]), objc_msgSend(self, sel)]];
                break;
            case 'f':
                [string appendString:[NSString stringWithFormat:@"%s : %f\n", property_getName(properties[i]), objc_msgSend(self, sel)]];
                break;
            default:
                break;
        }
    }
    
    free(properties);
    
    return string;

}

As you can see, I’m using this so that NSLog will give me something meaningful by overriding the description method of NSObject.
Edit: If you call this from a subclass, this method will only print the properties of the declared type!

Objective-C Quickie – Block variables

Blocks are becoming more and more preferred in iOS and Objective-c, with most of the UIView animations becoming block based and methods added to the NS collection classes to use blocks for enumeration. Blocks can also be stored as variables and used over and over again. This is immensely useful when subscribing to a DRY method of coding.

Below is some code I’m using to apply transformations to CALayers. I’ve got three sets of them, and since I simply want to apply the same transformation to them, I can write the block for creating and applying the transformation once, and use it on all three sets:

// this is a block variable
id transBlock = ^(id obj, BOOL *stop)
{
    CALayer *layer = (CALayer *)obj;
    CGAffineTransform trans = CGAffineTransformConcat([layer affineTransform],                                                       CGAffineTransformMakeTranslation(delta * 0.7, 0));
    [layer setAffineTransform:trans];
};

[displayedBars enumerateObjectsUsingBlock:transBlock];
[displayedBarLabels enumerateObjectsUsingBlock:transBlock];
[displayedAxisLabels enumerateObjectsUsingBlock:transBlock];

Drawing with CADisplayLink

For 90% of the animations you’ll ever need to do CoreAnimation or UIView animations are enough. Sometimes, the thing you want to animate can’t be handled by simple property based transitions or by moving an object along a path. Enter CADisplayLink:

From the CADisplayLink class reference:

A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.

The purposes that I need, I want to animate a circle similarly to how flex charts draws pie charts (a “swipe open” kind of animation). For the demo, though, I’ll simply use the CADisplayLink to animate a line extending across the screen on a CALayer using it’s drawInContext: method.

First the main view that contains my CALayer subclass:

//  MainView.h

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#import "AnimationLayer.h"

@interface MainView : UIView 
{
    AnimationLayer *alayer;
}

@end
//  MainView.m

#import "MainView.h"

@implementation MainView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

- (void)didMoveToSuperview
{
    if ([self superview])
    {
                
        alayer = [[AnimationLayer alloc] init];
        alayer.frame = self.frame;
        [self.layer addSublayer:alayer];
        
    }
}

And next the CALayer that will be animated:

//  AnimationLayer.h

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface AnimationLayer : CALayer 
{
    CADisplayLink *displayLink;
}

@end
//  AnimationLayer.m
#import "AnimationLayer.h"

static bool _running;

@implementation AnimationLayer

- (id)init
{
    self = [super init];
    if (self)
    {
        displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain];
        [self setNeedsDisplayOnBoundsChange:YES];
    }
    
    return self;
}

static CGPoint lastPoint = {0, 0};
- (void)drawInContext:(CGContextRef)ctx
{
    if (!_running)
    {
        [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
        _running = YES;
        return;
    }

    CGContextSetStrokeColorWithColor(ctx, [[UIColor blackColor] CGColor]);
    
    CGRect rect = CGContextGetClipBoundingBox(ctx);
    
    CGContextMoveToPoint(ctx, 0, 0);
    lastPoint.x = lastPoint.y += 1;
    CGContextAddLineToPoint(ctx, lastPoint.x, lastPoint.y);
    CGContextStrokePath(ctx);
    
    if (lastPoint.x == rect.size.width)
    {
        [displayLink invalidate];
        _running = NO
    }
}

@end

The main view is pretty uninteresting as it only creates a new CALayer and adds it as a sublayer of itself.

The animation layer holds the CADisplayLink as an Ivar and initializes it with the layer’s drawInContext: method.

We need some kind of flag to tell the CADisplayLink when to stop updating, for this I used a static BOOL _running. On the first pass of drawInContext, we’ll add the display link to the main run loop, at which point it will start calling the specified selector. We’ll set the _ruinning flag to true and return. On every subsequent pass of drawInContext: we’ll draw a longer line running diagonally. At the end we’ll check the condition to invalidate the CADisplayLink; in this case I’ll check to see whether the line has fully crossed the screen. Once we invalidate the display link the animation will stop.

This is a simple example, but it shows how you can animate an object using pure drawing for the times when property animations simply won’t do.

Elastic dragging with a CALayer

You’ll notice when you pull beyond the bounds of a UITableView that the table view appears spring loaded before jumping back when you lift your finger off the device. I posted a project to GitHub that illustrates something similar using a CALayer and the UITouch event handlers on UIView.

There’s a few strange things I did using a category on UIWindow to handle the touch events, but you could implement the same functionality on any UIView. The important things are the touch callbacks which are posted below.

static BOOL tapOnImageLayer;
static CGPoint initialPosition;
static float velocity = 900; // px / sec

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (tapOnImageLayer)
    {
        CALayer *imageLayer = [(elasticAppDelegate_iPhone *)[UIApplication sharedApplication].delegate imageLayer];
        
        CGFloat distance = CGPointDistance(initialPosition, imageLayer.position);
        
        NSTimeInterval time = distance / velocity;
        NSLog(@"%f %f", distance, time);
        [CATransaction begin];
        [CATransaction setDisableActions:NO];
        [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
        [CATransaction setAnimationDuration:time];
        
        imageLayer.position = initialPosition;
        
        [CATransaction commit];
        
        tapOnImageLayer = NO;
    }
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *t = [touches anyObject];
    CALayer *layer = [self.layer hitTest:[t locationInView:self]];
    if (layer == [(elasticAppDelegate_iPhone *)[UIApplication sharedApplication].delegate imageLayer])
    {
        tapOnImageLayer = YES;
        initialPosition = layer.position;

    }
    else
    {
        tapOnImageLayer = NO;
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    if (tapOnImageLayer)
    {
        CALayer *imageLayer = [(elasticAppDelegate_iPhone *)[UIApplication sharedApplication].delegate imageLayer];
        
        CGSize delta = CGSizeMake([touch locationInView:self.window].x - initialPosition.x, 
                                  [touch locationInView:self.window].y - initialPosition.y);
        
        [CATransaction begin];
        [CATransaction setDisableActions:YES];
        
        imageLayer.position = CGPointOffset(initialPosition, CGSizeMultiplyScalar(delta, 0.7));
        
        [CATransaction commit];
    }
}

The important parts are setting the desired spring back velocity in line 3, and scaling the drag position in line 56. There are a couple of convenience functions for working with the CGFoundation types:

CGPoint CGPointOffset (CGPoint point1, CGSize delta)
{
    CGPoint p;
    p.x = point1.x + delta.width;
    p.y = point1.y + delta.height;
    
    return p;
}

CGFloat CGPointDistance (CGPoint p1, CGPoint p2)
{
    CGFloat dx = p1.x - p2.x;
    CGFloat dy = p1.y - p2.y;
    
    return sqrtf(dx * dx + dy * dy);
}

CGSize CGSizeMultiplyScalar (CGSize p, CGFloat scalar)
{
    return CGSizeMake(p.width * scalar, p.height * scalar);
}

I’ll post this and the other code I’ve done on Github shortly (I’m pretty new to it and still trying to figure it out!)

Search the developer docs from the Chrome Omnibar

ClickOnTyler posted a couple of helpful Chrome extensions for searching apple’s documention directly from the Omnibar. Simply type “ios UIImage” or “mac NSApplication” to search the apple docs. Very Handy!

Using an NSDictionary for storing a matrix of values

For a recent project I needed to store a matrix of data. My only requirement was that access would be fast given a row and column designation. Unfortunately, the usual approach of using arrays of arrays wouldn’t work because of how NSArray works. From the Apple documentation for NSMutableArray:

Note that NSArray objects are not like C arrays. That is, even though you specify a size when you create an array, the specified size is regarded as a “hint”; the actual size of the array is still 0. This means that you cannot insert an object at an index greater than the current count of an array.

I could have used C arrays, but I wanted something more flexible when it comes to size and I didn’t necessarily need the contiguous memory. Constant time access was good enough.

NSDictionaries provide constant time access, and the only requirements for keys are that the object used conform to NSCoding and implement a hash function, both of which are implemented by NSIndexPath.

For my example I’ll use the adapter pattern and wrap a dictionary and expose only the methods I want:

// PZMatrix.h
#import <Foundation/Foundation.h>

@interface PZMatrix : NSObject 
{
    @private
    NSMutableDictionary *_source;
}

- (id)initWithRows:(NSInteger)rows columns:(NSInteger)cols;
- (id)objectForRow:(NSInteger)row column:(NSInteger)col;
- (void)setObject:(id)object forRow:(NSInteger)row column:(NSInteger)col;
- (void)removeAllObjects;

@end

You can see that I’m using the NSDictionary as the only iVar in the class, and I’ve created a few accessors and mutators for the data structure.

// PZMatrix.m
#import "PZMatrix.h"

@implementation PZMatrix

- (id)initWithRows:(NSInteger)rows columns:(NSInteger)cols
{
    self = [super init];
    if (self)
    {
        _source = [[NSMutableDictionary alloc] initWithCapacity:rows *cols];
    }    
    return self;
}

- (id)objectForRow:(NSInteger)row column:(NSInteger)col
{
    NSUInteger idxs[] = {row, col};
    NSIndexPath *path = [NSIndexPath indexPathWithIndexes:idxs length:2];
    return [_source objectForKey:path];
}

- (void)setObject:(id)object forRow:(NSInteger)row column:(NSInteger)col
{
    NSUInteger idxs[] = {row, col};
    NSIndexPath *path = [NSIndexPath indexPathWithIndexes:idxs length:2];
    [_source setObject:object forKey:path];
}

- (void)removeAllObjects
{
    [_source removeAllObjects];
}

@end

Pretty simple. There’s obviously some code duplication here, some of which I can simplify with a category on NSIndexPath:

//  NSIndexPath+Matrix.h
#import <Foundation/Foundation.h>

@interface NSIndexPath (Matrix)

+ (NSIndexPath *)indexPathWithRow:(NSUInteger)row column:(NSUInteger)col;

@end

//  NSIndexPath+Matrix.m
#import "NSIndexPath+Matrix.h"

@implementation NSIndexPath (Matrix)

+ (NSIndexPath *)indexPathWithRow:(NSUInteger)row column:(NSUInteger)col
{
    NSUInteger indexes[] = {row, col};
    return [NSIndexPath indexPathWithIndexes:indexes length:2];
}

@end

I can now pull that category into the matrix storage class:

// PZMatrix.m
#import "PZMatrix.h"
#import "NSIndexPath+Matrix.h"

@implementation PZMatrix

- (id)initWithRows:(NSInteger)rows columns:(NSInteger)cols
{
    self = [super init];
    if (self)
    {
        _source = [[NSMutableDictionary alloc] initWithCapacity:rows *cols];
    }    
    return self;
}

- (id)objectForRow:(NSInteger)row column:(NSInteger)col
{
    NSIndexPath *path = [NSIndexPath indexPathWithRow:row column:col];
    return [_source objectForKey:path];
}

- (void)setObject:(id)object forRow:(NSInteger)row column:(NSInteger)col
{
    NSIndexPath *path = [NSIndexPath indexPathWithRow:row column:col];
    [_source setObject:object forKey:path];
}

- (void)removeAllObjects
{
    [_source removeAllObjects];
}

@end

Testing the implementation:

PZMatrix *matrix = [[PZMatrix alloc] initWithRows:10 columns:10];
[matrix setObject:@"foo" forRow:2 column:8];
[matrix setObject:@"bar" forRow:0 column:9];
[matrix setObject:@"baz" forRow:9 column:9];
    
NSLog(@"%@", [matrix objectForRow:2 column:8]);
NSLog(@"%@", [matrix objectForRow:9 column:9]);
NSLog(@"%@", [matrix objectForRow:9 column:8]);