Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Completion handlers and return values

I want to call a method which will return a value from its completion handler. The method performs asynchronously and I don't want to return a value before all the body of the method has been executed. Here is some faulty code to illustrate what I am trying to achieve:

// This is the way I want to call the method
NSDictionary *account = [_accountModel getCurrentClient];

// This is the faulty method that I want to fix
- (NSDictionary *)getCurrentClient
{
    __block NSDictionary *currentClient = nil;
    NXOAuth2Account *currentAccount = [[[NXOAuth2AccountStore sharedStore] accounts] lastObject];

    [NXOAuth2Request performMethod:@"GET"
                        onResource:[NSURL URLWithString:[NSString stringWithFormat:@"%@/clients/%@", kCatapultHost, currentAccount.userData[@"account_name"]]]
                    usingParameters:nil
                        withAccount:currentAccount
                sendProgressHandler:nil
                    responseHandler:^ (NSURLResponse *response, NSData *responseData, NSError *error) {
                        NSError *jsonError;

                        currentClient = [NSJSONSerialization JSONObjectWithData:responseData
                                                                        options:kNilOptions
                                                                            error:&jsonError];
                    }];

    return currentClient;
}

I don't want the getCurrentClient method to return a value until the NXOAuth2Request has finished. I can't return the current client inside the response handler of the request either. So what are my options?

like image 487
Robert Audi Avatar asked Apr 27 '13 17:04

Robert Audi


People also ask

What is difference between closure and completion handler Swift?

Closures are self-contained blocks of functionality that can be passed around and used in your code. Said differently, a closure is a block of code that you can assign to a variable.

Is a Completion Handler a closure Swift?

A completion handler is nothing more than a regular closure that's called to indicate that some piece of work has completed or produced a result. The completion handler that you pass to the dataTask function (in this case via trailing closure syntax) is called once the data task completes.

What is completion handler in Swift?

A completion handler in Swift is a function that calls back when a task completes. This is why it is also called a callback function. A callback function is passed as an argument into another function. When this function completes running a task, it executes the callback function.

What is completion @escaping?

This means that the completion closure won't be executed until after makeRequest(_:) has exited its scope and the closure outlives it. In short, @escaping is used to inform callers of a function that takes a closure that the closure might be stored or otherwise outlive the scope of the receiving function.


1 Answers

You need to change getCurrentClient to take in a completion block instead of returning a value.

For example:

-(void)getCurrentClientWithCompletionHandler:(void (^)(NSDictionary* currentClient))handler
{
    NXOAuth2Account *currentAccount = [[[NXOAuth2AccountStore sharedStore] accounts] lastObject];

    [NXOAuth2Request performMethod:@"GET"
                        onResource:[NSURL URLWithString:[NSString stringWithFormat:@"%@/clients/%@", kCatapultHost, currentAccount.userData[@"account_name"]]]
                   usingParameters:nil
                       withAccount:currentAccount
               sendProgressHandler:nil
                   responseHandler:^ (NSURLResponse *response, NSData *responseData, NSError *error) {
                        NSError *jsonError;

                        NSDictionary* deserializedDict = [NSJSONSerialization JSONObjectWithData:responseData
                                                                                         options:kNilOptions
                                                                                           error:&jsonError];
                        handler(deserializedDict);
                }];
}

It's important to remember that getCurrentClient will return immediately, while the network request is dispatched on another thread. Don't forget that if you want to update the UI using your response handler, you need to have your handler run on the main thread.

like image 197
Tim Avatar answered Oct 17 '22 20:10

Tim