6

I have an object which takes a long time to do some stuff (it downloads data from a server).

How can I write my own completion block so that I can run...

[downloader doSomeLongThing:^(void) {
    //do something when it is finished
}];

I'm not sure how to save this block in the downloader object.

Fogmeister
  • 70,181
  • 37
  • 189
  • 274
  • Are you just wondering how to write a method that accepts a block? http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1 – James Boutcher Jan 29 '13 at 15:43
  • Now I understand why certain people tag stuff with Xcode (although that's wrong, anyway), but 'greatest-common-divisor'... How come? –  Jan 29 '13 at 15:44
  • LOL! I didn't put that tag. I put GCD as in Grand Central Dispatch. It must have changed it. – Fogmeister Jan 29 '13 at 15:46

2 Answers2

10

You can copy the block then invoke it:

typedef void (^CallbackBlk)();

@property (copy) CallbackBlk cb;

- (void)doSomething:(CallbackBlk)blk
{
    self.cb = blk;

    // etc.
}

// when finished:
self.cb();
7

Since you're not using any parameters in your callback, you could just use a standard dispatch_block_t and since you just want to call back to it when your long process has completed, there's no need to keep track of it with a property. You could just do this:

- (void)doSomeLongThing:(dispatch_block_t)block
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Perform really long process in background queue here.

        // ...

        // Call your block back on the main queue now that the process 
        // has completed.
        dispatch_async(dispatch_get_main_queue(), block);
    });
}

Then you implement it just like you specified:

[downloader doSomeLongThing:^(void) {
    // do something when it is finished
}];
Matt Long
  • 23,982
  • 4
  • 70
  • 99
  • Thanks, I will keep this for future reference. In my actual code there are a couple of parameters and I need two different blocks. It's for the completion/error of an NSURLConnection but it's one that I can't use sendAsynch... with. – Fogmeister Jan 29 '13 at 16:52
  • I see. You might also consider looking at AFNetworking in that case. There are debates as to whether these libraries make things better or not. In my opinion, the blocks based APIs make AFNetworking a very simple and convenient library to use. You can take a look at it here: https://github.com/AFNetworking/AFNetworking and decide for yourself. – Matt Long Jan 29 '13 at 17:23
  • Thanks. I'll take a look. I've created my class now and it seems to be working well but I'll consider it for the future. – Fogmeister Jan 29 '13 at 17:25
  • Can someone take a look at my related question here: http://stackoverflow.com/questions/21269848/what-makes-a-completion-handler-execute-the-block-when-your-task-of-interest-is – marciokoko Jan 21 '14 at 21:53