cdub cdub - 5 months ago 131
iOS Question

How can I wait for a completion block to finish in objective-c ios

I have a subclass with two methods:

- (void) aPostRequest:(NSString *) urlStr andJSON:(NSMutableDictionary

*) jsonDict completion:(void (^)(NSDictionary *, NSError *))completion
{
NSError *error = nil;

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];

[request setHTTPMethod:@"POST"];

[request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request addValue:@"application/json" forHTTPHeaderField:@"Accept"];

// Set up the post data
NSData *postData = [NSJSONSerialization dataWithJSONObject:jsonDict options:0 error:nil];
[request setHTTPBody:postData];

// dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
if (!error)
{
// convert the NSData response to a dictionary
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

if (error)
{
// There is a parse error
completion(nil, error);
}
else
{
// Success
completion(dictionary, nil);
}
}
else
{
// Error from the session
completion(nil, error);
}

// dispatch_semaphore_signal(semaphore);
}];

// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

[postDataTask resume];
}


And this method that calls the method above:

- (NSString *) verifyUnique
{
// JSON data
__block NSString *verifyUnique = nil;

// dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

// URL string
NSString *url = @"https://the-website-to-handle-this.com";
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
[json setValue:@"testing" forKey:@"name"];

[self aPostRequest:url andJSON:json completion:^(NSDictionary *response, NSError *error)
{
// dispatch_semaphore_signal(semaphore);

if (!error) {

} else {

verifyUnique = [response objectForKey:@"uniqueness"];

// return verifyUnique;
// dispatch_semaphore_signal(semaphore);
}
}];

// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

return verifyUnique;
}


I call the function from another view controller class and call [thisClass verifyUnique]; and want it to wait till the answer gets returned. Before it was called in the view controller the UI gets handled with an activity indicator so we can wait. How do I wait for both compltion blocks to return?

Answer
- (void *) verifyUniqueCompletion:(void (^)(NSString *result, NSError *error))completion
{
    // JSON data
    __block NSString *verifyUnique = nil;

    // dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

    // URL string
    NSString *url = @"https://the-website-to-handle-this.com";
    NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
    [json setValue:@"testing" forKey:@"name"];

    [self aPostRequest:url andJSON:json completion:^(NSDictionary *response, NSError *error)
     {
         // dispatch_semaphore_signal(semaphore);

         if (!error) {
             completion(nil, error);
         } else {  

             verifyUnique = [response objectForKey:@"uniqueness"]; 

             completion(verifyUnique, nil);
             // return verifyUnique;
             // dispatch_semaphore_signal(semaphore);
         }
     }];

    // dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

}

Use this:

[thisClass verifyUniqueCompletion:^(NSString *result, NSError) {
    NSLog(@"result: ", result);
}];