Ruofeng
Ruofeng

Reputation: 2350

Confusion about iOS blocks

I'm not sure how to deal with blocks. For example, in my viewDidLoad I called a function "useDocument" to set up Core Data. I hope that as soon as Core Data is ready to use, another function is called to handle some query. Just like ASIHTTPRequest, when the client receives the response, a function is called to handle the response.

I guess triggering a function is not the right way to work with blocks. But what's the right way?

- (void)useDocument
{
    if (!self.database) {
        self.database = [DataModelDocument sharedDocument];
    }

    if (![[NSFileManager defaultManager] fileExistsAtPath:[self.database.fileURL path]]) {
        // does not exist on disk, so create it
        [self.database saveToURL:self.database.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
                if (!success) {
                    NSLog(@"database doesn't exist on disk, we fail to create it");
                }
        }];
    } else if (self.database.documentState == UIDocumentStateClosed) {
        // exists on disk, but we need to open it
        [self.database openWithCompletionHandler:^(BOOL success) {
            if (!success) {
                NSLog(@"database exists on disk, but we fail to open it");
            }
        }];
    } else if (self.database.documentState == UIDocumentStateNormal) {
        // already open and ready to use
    }
}

Upvotes: 0

Views: 752

Answers (2)

There is no right way to use a block, as there is no right way to use a function.

Blocks are functions. A bit more than a function, but not a whole lot different. So let's forget the differences for now. Functions.

Using a function, you'll write something like

void callback (BOOL success) {
    if (success) {
        // do something useful
    }
}

[database openWithCallback: &callback];

Some kind of little endianess here. ish.

Blocks allow you to write your callbacks in line.

[self.database openWithCompletionHandler: ^(BOOL success) {
    if (!success) {
        // oops, handle that
    }
}];

In that particular case, blocks do not solve any problem functions couldn't. They cost more even.

The benefits show themselves when you use a lot of them. If you write your operations to be fully asynchronous, you can write your code in a streamlined fashion.

pseudo-code:

dispatch block: ^(){
    some heavy computation here
    dispatch block: ^(){
        computation done, update the UI or something
    }
}

Very simple example. Writing this with functions is completely possible of course. But not as readable.

Now imagine you are dispatching tons of blocks, you can create groups of blocks then execute a block when the group is fully executed. Very easy to write, very easy to read. This starts to be a nightmare dealing with function pointers everywhere.

And now, what makes a block more than a function?

A block is a function. With a context. A block can access variables in the same scope. In the simple exemple above, the work block have access to the calling scope, and the completion block to the calling scope and work block scope. This is can be done with functions and structures of course. With a lot of code, much harder to read. Blocks solve that more elegantly.

I suggest you read about Grand Central Dispatch. This is clearly where blocks show their true potential and expressiveness.

Upvotes: 1

Matt Hudson
Matt Hudson

Reputation: 7358

You can think of a block as sort of a "stateful thread". I stress "sort of". It is code and variables encapsulated into a nice neat little "block" of code.

You can use __block to bring variables into scope from outside the block and the block runs when the rest of the surrounding code is completed.

In this case you are using completion blocks. You can call methods in there if you like as long as the appropriate time to call them is after all of the code around it is completed.

Upvotes: 0

Related Questions