Thinking about better block syntax (kind-of)

26 Mar

I’m pretty sure we can all agree that block syntax in Objective-C (or rather C) is pretty bad. There’s plenty of evidence.

I use a set of code snippets to help get around this.
Using shorthand like blockLocalVariable that expands to:

<#returnType#> (^<#blockName#>)(<#parameterTypes#>) = ^<#returnType#>(<#parameters#>){
};

However, today I was wondering if macros might be able to help solve this better.
After a little bit of playing around I came up with this…

#define blockParameters(parameters...) parameters

#define block(__blockName__, __returnType__, __blockParameters__, __func__) \
            __returnType__ (^__blockName__)(__blockParameters__) = ^__returnType__(__blockParameters__)__func__

You use it like so:

block(myBlock, int, blockParameters(int a, int b), {
    return a + b;
});

int c = myBlock(1, 2);

While not exactly ideal. It was a somewhat fun exercise.

Better View Controller callbacks with Blocks

5 Jan

So you’re working on an app and it needs to present a UIPopoverController to give your user some choices. Maybe your app provides a popover for the user to pick their height. Whenever the user picks a new height in the popover this selection needs to be communicated back to your main UIViewController so it can update it’s interface.

Easy, just make a custom UIViewController for the height picker and expose a delegate @protocol. Then, whenever the user picks a new height, the custom HeightViewController will call the delegate’s selection handler.

Here’s an example of what our HeightViewController interface might look like

@import UIKit; @class HeightViewController; @protocol HeightViewControllerDelegate <NSObject> - (void)heightViewController:(HeightViewController *)heightViewController didSelectHeight:(NSNumber *)selectedHeight; @end @interface HeightViewController : UIViewController @property (nonatomic, strong) NSNumber *height; @property (nonatomic, weak) id<HeightViewControllerDelegate> delegate; @end

And the interesting part of it’s @implementation

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    if ([self.delegate respondsToSelector:@selector(heightViewController:didSelectHeight:)]) {
        NSNumber *height = self.pickerArray[row];
        [self.delegate heightViewController:self didSelectHeight:height];
    }
}

Then in our main view controller…

- (void)heightViewController:(HeightViewController *)heightViewController didSelectHeight:(NSNumber *)selectedHeight {
    self.height = selectedHeight;
}

This is all working great, one simple UIViewController subclass and you’ve exposed just what’s needed to update the main view.

Then the next day comes…now you need to allow the user to pick their weight. “No problem!” you say. So you merrily create another UIViewController subclass called WeightViewController and add another delegate callback to your main view controller.

Then another day passes…and you need to expose a department picker, a title picker and date picker, or two, or three, or four, before you know it you’ve made a dozen custom view controllers and littered your main view controller with code to configure and handle all the selection callbacks. Things are starting to get out of hand.

There’s a better way.

BLOCKS. Rather than exposing a @protocol for each picker let’s try using BLOCKS for our callbacks.

Take our custom HeightViewController.h for example.

@import UIKit;

typedef void (^HeightViewControllerSelectionHandler)(NSNumber *selectedHeight);

@interface HeightViewController : UIViewController

@property (nonatomic, strong) NSNumber *height;
@property (readwrite, copy) HeightViewControllerSelectionHandler selectionHandler;

@end

Pretty simple huh? We’ve removed the @protocol and delegate code. Now we just expose a selectionHandlerblock property that our main view controller will use to update itself.

Now lets look at how that changes our HeightViewController.m @implementation

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    // A quick check to see if we have a selectionHandler block
    if (self.selectionHandler) {
        NSNumber *height = self.pickerArray[row];
        self.selectionHandler(height); // it's that simple to use the callback block
    }
}

Finally in our main view controller. Instead of having separate code to create, configure and response to the delegate callback we handle it all during the creation of the HeightViewController

// Alloc and init the height picker view controller
HeightViewController *heightViewController = [[HeightViewController alloc] initWithNibName:@"HeightViewController" bundle:[NSBundle mainBundle]];

// configure it's initial height
heightViewController.height = self.height;

// set our block callback
heightViewController.selectionHandler = ^(NSNumber *selectedHeight){
    self.height = selectedHeight;
};

// Present the height picker popover
self.popover.contentViewController = heightViewController;
[self.popover presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

No more delegate callbacks littered all throughout your main view controller. As an added bonus we get to keep the callback code with the alloc / init code, so our code’s sequence of events is clearer.

I’m not saying you should always use blocks instead of delegates, but in this case it seems like a good choice.

A desk, OS X Server, and Xcode

17 Nov

So after 3 years I finally got around to building a desk for my home office and I think it turned out quite good. I’ve got plenty of space to work and its given me a place dedicated to my software development. It’s important to get into the right mindset when you need to get work done at home, otherwise you’ll get distracted by all sorts of things.

However, after just a few short days of working I quickly realized a problem that I’ve ignored for far too long. Version control. Sure, I’ve done the occasional commit in Xcode to the local repo, snapped a snapshot here and there before some scary project change. But I never really bothered to dive deep into it because my laptop was both my daily driver and my development machine.

Things are changing now though. Thanks to my desk I finally have a real work area that I can use my Mac Pro at. Don’t get me wrong, I’ve gotten a lot of development done on my 15″ MacBook Pro and Xcode has grown into a first class citizen on it. But there’s still a world of difference between working on a 15″ screen vs a 24″ screen in Xcode, specially when it comes to storyboards.

So now, while I’m starting to get most of my work done on the MacPro, I would still like the ability to do some work while I travel with my MBP.

Enter OS X Server. Apple recently started giving OS X Server to iOS Developers for free to promote Xcode’s continuous integration (bots). But OS X Server also has another service for Xcode that is equally as good. Server hosted Repositories. So if you’re an indie developer like myself and you have both a desktop and laptop you can host your own Repo on your desktop and access it from both your desktop and laptop. Actually you can host as many Repos as you like, and if you add the “Sever” to your accounts in Xcode’s preferences it will automatically list the available Repos you create on the Sever. This makes for stupidly fast syncing across the local network. For now I have to remember to do a Pull on my MBP before I leave the house if I intended to work while I’m away. It’s a minor nuance and I’m considering getting a static IP for my desktop anyway which would fix that.

I’ve barely scratched the surface of OS X Server’s Xcode integration, much less all the other services it has to offer. I’m looking forward to seeing what else I can do to help automate my workflow.

office