xonegirlz
xonegirlz

Reputation: 8977

function return value from block

What if I have a function that returns an int and the return value of the int is taken from the block?

For example:

- (int) queryForKey:(NSString *)aKey view:(UIButton *)aView countView:(UIView *)aCountView counter:(int) count {
    //some initialization
    [query countObjectsInBackgroundWithBlock:^(int number, NSError * error) {
        [aCountView addSubview:self.generateCountLabel];

        if (number > 0){
            [aView setUserInteractionEnabled:YES];
            [aView setEnabled:YES];
        }
        //return number; //doing this will generate an error
    }];
}

also another question is, what if I have an int passed in as an argument of the function above and I would like to assign a value to it. Is some thing like that even possible?

Upvotes: 1

Views: 1429

Answers (3)

Joel Fischer
Joel Fischer

Reputation: 6597

I've found a better solution. Hopefully this will help someone else who stumbles across the question. I would implement a solution to your code like so:

- (int) queryForKey:(NSString *)aKey view:(UIButton *)aView countView:(UIView *)aCountView counter:(int) count {
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    __block int number;

    //some initialization
    [query countObjectsInBackgroundWithBlock:^(int number, NSError * error) {
        dispatch_async(queue, ^{
            [aCountView addSubview:self.generateCountLabel];

            if (number > 0){
                [aView setUserInteractionEnabled:YES];
                [aView setEnabled:YES];
            }
            dispatch_semaphore_signal(sema);
        });
    }];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    return number; //doing this will no longer generate an error
}

Then encapsulate your call with another dispatch_async so that your semaphore wait call doesn't block the main thread.

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
    [self queryForKey:@"AKey" view:myView countView:myCountView counter:aCounter];
});

Upvotes: -1

bbum
bbum

Reputation: 162722

The problem is that you have a synchronous method (one that wants to return the value immediately) that needs to return a value derived from an asynchronous method (one that goes about it's business in a different thread).

There are a couple of ways of fixing this:

  • wait for the countObjectsInBackgroundWithBlock: method to complete, use the __block pattern as @simonpie described.

  • replace the return number; with a call to something somewhere interested in the resulting number. This also means that queryForKey:view:countView: will likely return void.

The latter is the preferred solution as it will not block the thread calling the queryForKey:... method.

Note that you can't diddle UIKit classes on anything but the main thread. If that block is executed on a background thread, then doing what you are doing in the block is invalid.

Upvotes: 1

simonpie
simonpie

Reputation: 354

Well your block does not have a return value, it returns void.

To return a value you could use the __block modifier on a variable outside your block and store then answer there which can then be used by the rest of your method (or code).

Upvotes: 1

Related Questions