Friday, 11 February 2011

[ios] Dynamic cast in Objective-C

In C++, you can cast a pointer between two (related) types, and ask the runtime to check if the conversion is valid using dynamic_cast. Usually in C++ the use of dynamic_cast is a sign that you're doing something wrong - good C++ design generally avoids such constructs.

However, Objective-C is a far more dynamic language, and often you do need to do something similar. The runtime provides all the smarts for this, but doesn't deliver it in a simple one-liner.

So let's fix that...

Wondering if a view controller's view property is a UISwitch? Try this:
UISwitch *switch
= objc_dynamic_cast(UISwitch,viewController.view);
if (switch) NSLog(@"It jolly well is!);
That's nice, isn't it? Here's how:
#define objc_dynamic_cast(TYPE, object) \
({ \
TYPE *dyn_cast_object = (TYPE*)(object); \
[dyn_cast_object isKindOfClass:[TYPE class]] ? dyn_cast_object : nil; \
})

For the curious, here's what's going on...

First, we define a preprocessor macro using a gcc extension: the macro compound statement. That's the ({ ... }) block. This is a little dirty, and I certainly wouldn't use a gcc-specific extension in my "portable" C++ code. However, Objective-C lives in a different ecosystem, where you can guarantee that compound statements will be supported. So we'll go with it.

The reason I use a compound statement is to define a "local" variable - dyn_cast_object. This is just to cover the macro's back - it needs to mention the name of the object argument twice, and if that expression has side effects you'd get twice the number of side effects otherwise. Side-side effects. So I store the argument in a local variable to avoid this. (Most of the time this is unlikely to be an issue, but if you ever got bit by this problem, you'll appreciate having done it right the first time).

Then we simply ask the object is it is of the class of our cast's destination type, using NSObject's isKindOfClass: selector.

Not too complex. And you could do the isKindOfClass: dance wherever you need to cast. But it's nice to write the macro once and then write clear code that reveals it's intent.

[ios] Cancelling a UIGestureRecognizer

You have a view with a handful of gesture recognizers. Perhaps some of them are chained together with requireGestureRecognizerToFail so that they interact well.

Sometimes, you still need to respond to other user interaction, and cause any pending gesture to immediately fail. There isn't an API for that.

I had this issue when my application's "timeline" view, which was using pinch, tap, and pan gestures in concert, needed to grow temporary UIButton subviews. The buttons worked fine, but pressing them also triggered the gesture recognizers - very confusing for the user.

Here's the solution.

How to forcibly cancel a UIGestureRecnogizer

Add a new category (I call it "Cancel") to the UIGestureRecognizer class extending it with a new cancel method:
@interface UIGestureRecognizer (Cancel)
- (void)cancel;
@end
And implement the new method like this:
@implementation UIGestureRecognizer (Cancel)
- (void)cancel
{
self.enabled = NO;
self.enabled = YES;
}
@end
The simple trick of switching off and back on a gesture will force it to cancel.

Then for bonus points, I add a category on UIView to make it easy to cancel all the gestures attached to it. I tend not to hold the gestures as member variables in my view controller because there isn't any need to do so - they are retained by the view you attach them to.
//-----------------------------------------
// In .h file:

@interface UIView (CancelAllGestures)
- (void) cancelAllGestureRecognizers;
@end

//-----------------------------------------
// In .m file:

@implementation UIView (CancelAllGestures)
- (void) cancelAllGestureRecognizers
{
for (UIGestureRecognizer *gesture in self.gestureRecognizers)
{
[gesture cancel];
}
}
@end
This new method could then be easily used in my main view controller, by attaching it to the my UIButton objects as a new action:
[button addTarget:myViewWithGestures
action:@selector(cancelAllGestureRecognizers)
forControlEvents:UIControlEventTouchDown];

Categories are a useful Objective C feature that really do help to make your code more clear and readable. Here they provide the means for another simple solution. I hope you find it useful.

Friday, 4 February 2011

So you need some software?


This is your handy cut-out-and-keep guide to software development.

Click on the image for high-res version.

PGMidi updated

Attention PGMidi users! I've updated my MIDI Monitor example project again, this time making PGMidi less of an example, and a lot more useful for general use.

Check it out on the GitHub project page (historical note: it was hosted on this gitorious project page, but that is now deprecated in favour of GitHub).

What's changed:
  • The PGMidi class now allows you to determine what MIDI sources and MIDI connections are currently available.
  • It allows you to determine whether the source/destination is a networked session, or a physically attached device.
  • The "events" PGMidi sends through the delegate interface are far more explicit.
  • I've added some useful tools to find a matching source/destination pair if you want to speak to one specific MIDI device.
The MIDIMonitor example application continues to show how to use the PGMidi API.

Thanks for all the comments and feedback I've received about this code. I hope you find these updates useful.

Friday, 28 January 2011

Speaking: BCS Edinburgh (iOS development)


I will be speaking at the Edinburgh branch of the BCS on the subject of iPhone development on March the 9th.

The details of the session, times, and location are available here.

Here's the synopsis:

Developing applications for iPhone, iPad (and other iOS devices)
"An introduction to iPhone development for beginners or those who are casually interested and want a leg up the learning curve"

The iPhone, iPad and their iOS relatives are becoming an increasingly popular and important platform. More and more developers are looking into what the platform can offer and how to harness its power for their products.

In this presentation, an experienced iOS developer provides a boot-strap in iPhone development. The talk is an overview of how to get started as an iPhone developer. You will gain an understanding of the platform, the tools, and the core technologies, including:
  • The main languages: Objective C/C++
  • Using the Xcode IDE, and various deployment/testing tools
  • Common iPhone/Mac OS design patterns, idioms, and practices
  • Becoming a native: how to "think in iPhone"
  • An overview of the libraries and facilities that exist
  • Limitations of the development environment.
We'll see the pros and cons of iPhone development. You will leave with an understanding of how to deploy your applications on the device, and whether it is the right platform for you to target.

Thursday, 27 January 2011

iOS: performSelectorOnMainThread: with two arguments

iOS's NSObject class provides a mechanism to run any selector on a different thread. The most often used variant runs the selector on the "main" (i.e. UI) thread, the snappily titled: performSelectorOnMainThread:withObject:waitUntilDone:. However, the limitation with this call is that you can only supply one argument.

Sometimes, one is not enough. There is a two argument non-thread version, here. So why not invent our own two-argument threaded version?

We can add this easily enough to the base NSObject class by opening a new category on it just for the purpose.

Here's how...

1. Define our API

We open a category on NSObject (note the category name in brackets)
@interface NSObject (PGPerformSelectorOnMainThreadWithTwoObjects)
- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait;
@end
Naturally, it follows the existing performSelector API signatures, but just adds our extra withObject: argument.

2. Implement it

Here's the secret sauce. Careful application of NSMethodSignature, and NSInvocation.
@implementation NSObject (PGPerformSelectorOnMainThreadWithTwoObjects)
- (void) performSelectorOnMainThread:(SEL)selector withObject:(id)arg1 withObject:(id)arg2 waitUntilDone:(BOOL)wait
{
NSMethodSignature *sig = [self methodSignatureForSelector:selector];
if (!sig) return;

NSInvocation* invo = [NSInvocation invocationWithMethodSignature:sig];
[invo setTarget:self];
[invo setSelector:selector];
[invo setArgument:&arg1 atIndex:2];
[invo setArgument:&arg2 atIndex:3];
[invo retainArguments];
[invo performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:wait];
}
@end

That's it.

Now you have your own simple way to invoke a call to selector on the main thread from wherever you are in your code. Handy.

Wednesday, 26 January 2011

Speaking: ACCU 2011

I will be speaking at the ACCU 2011 developer conference in Oxford, UK in April.

This year, my ACCU presentation is called Becoming a Better Programmer (yes, following the title of my magazine column - but it's not the same content, honest!).

Here's the talk synopsis:
You're a programmer. You spend your life programming. (You dull person, you!)

Don't you want to do it as well as you possibly can?

This entertaining talk will provide a number of practical, simple methods to become a better programmer. There will be plenty of hand-waving and jumping, a little philosophy, and much wisdom from our excellent programmer forebears.

Be the best programmer you can!