Bringing Blocks to the iSQL SDK

We've had a couple of requests from customers of the iSQL SDK for a little more flexibility in receiving the callbacks when queries complete. For example, a class might spin off a couple of different SQL queries, and need some way of distinguishing which one has just returned. One way of doing this is to create another class, responsible for accepting the callback, but sometimes that's a bit overengineered. So we've just added a Blocks-based version of the API, and released this today.

If you've not used Blocks before, they're rather neat, and actually not too scary! If you're already an iOS 4 pro, and have been using Blocks since forever, you can skip the next bit. If not, read on...


A Block is just that - a block of code, and the state around it at the time it was instantiated (or copied to the heap; a subtle difference in our case, but sometimes important). Let's take a simple example:

typedef void(^myFirstBlock)(void);

- (void)myMethod {
    myFirstBlock block = ^{
        NSLog(@"Hello world");
    };

    block();
}

In the first line, we declare a block typedef: myFirstBlock is a type of block which takes no arguments, and returns nothing. In myMethod, we create a new block using the ^{ ... } syntax, and assign it to the local variable "block". We can then execute that block a bit later by calling block();.

Importantly, if our Block had used any local variables, they would be packaged up and kept with the Block as well - so extending our example slightly:

- (void)myMethod {
    int answer = 42;
    myFirstBlock block = ^{
        NSLog(@"The answer is %d", answer);
    };
   
    answer = 22;

    block();
}

In this example, we'll see "The answer is 42" printed - not 22. The value of answer was captured at the time the block was instantiated - not when it was executed.

We can pass blocks as arguments to methods, and blocks themselves can take arguments and have return types. In this example, we'll change our block to take a pair of integers:

typedef void(^myFirstBlock)(int,int);

- (void)methodTakingABlock:(myFirstBlock)block {
    block(4, 2);
}
- (void)myMethod {
    [self methodTakingABlock:^(int a, int b) {
        NSLog(@"Doing something with %d and %d", a, b);
    }];
}

You might start to see where this is going... we can pass a block of arbitrary code to another method - perhaps in a 3rd party API - which is then called some time later, supplying some extra data at that point.

That'll do for the moment as an introduction to Blocks - if you'd like to find out more, there's a nice introduction, and some more in-depth tips, both of which I'd recommend having a look through.


So why is this useful for the iSQL SDK? It means that rather than needing to have a fixed callback method for everything (sqlQueryDidFinishExecuting), you can now specify a separate method to be called for each query you fire off. In the past, you needed to rely on passing some metadata around with a query - either a numeric or string ID - and then in the delegate callback, there was inevitably a big switch(...) statement to deal with each of the paths. Now, you can fire each query's results straight to the right logic.

Depending on your style, you might prefer to write that code inline:

- (void)myMethod {
    [self.sqlClient executeQuery:@"SELECT 1;" withCompletionBlock:^(SqlClientQuery *query) {
        NSLog(@"Query completed!");
    }];
}

...or you might prefer to pass the result straight on to another regular method:

- (void)myQueryFinished:(SqlClientQuery *)query {
    NSLog(@"Query finished!");
}

- (void)myMethod {
    [self.sqlClient executeQuery:@"SELECT 1;" withCompletionBlock:^(SqlClientQuery *query) {
        [self myQueryFinished:query];
    }];
}

One of the suggestions we had on the forum was to add a "title" to the query, which you could get at when it finished. With Blocks, you can do exactly that!

- (void)myQueryFinished:(SqlClientQuery *)query withTitle:(NSString *)title {
    NSLog(@"Query '%@' finished!", title);
}

- (void)myMethod {
    NSString *title = @"basic query";
    [self.sqlClient executeQuery:@"SELECT 1;" withCompletionBlock:^(SqlClientQuery *query) {
        [self myQueryFinished:query withTitle:title];
    }];
}

If you're an existing iSQL customer, you can visit the URL in your "thanks for purchasing" email again to grab the new version. If you've not yet bought the component, you can go and grab a new download of the trial version, and start enjoying the Blocks-based API right now...

Posted by

Comments (2)

Nov 22, 2011
Brandon said...
I finally took some time to read this and try to understand... wish I had done it earlier...
Nov 22, 2011
Brandon said...
Yep... I reiterate... blocks are absolutely awesome!

Leave a comment...

Contributors

Tags

Archive

2011 (25)