0

I'm new to iOS and I have trouble understanding and applying well dispatch ... I have an application I need to query a website (api) within a for loop, the end of that cycle I need to make further inquiries in another cycle, and finally, at the end of both cycles need to switch views.

I now have this code (after much trial and error but still does not work):

dispatch_queue_t queue = dispatch_queue_create("threadServicios", DISPATCH_QUEUE_SERIAL);

    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);

    dispatch_async(queue, ^(void) {
        NSLog(@"llego a buscar servicios por local");
        for (NSDictionary *local in _arrLocalesTmp) {
            [self getListaServiciosPorLocal:[local objectForKey:@"idLocal"]];
            //this function calls another function that consumes a web service and get a json
        }

        procced = YES;

        NSLog(@"llego a buscar profesionales por local");
        for (NSDictionary *local in _arrLocalesTmp) {
            [self getListaProfesionalesPorLocal:[local objectForKey:@"idLocal"]];
            //this function calls another function that consumes a web service and get a json
        }

        procced2 = YES;

        dispatch_group_leave(group);
    });

    dispatch_group_notify(group, dispatch_get_main_queue(),^{
        NSLog(@"dispatch procced 1");
        if (procced && procced2) {
            [self setFormularioConsultaCompleto];
        }
    });

The function [self getListaServiciosPorLocal: [Local objectForKey: @ "idLocal"]]; is as follows:

dispatch_async(dispatch_get_main_queue(), ^(void) {
    NSURL *url = [NSURL URLWithString:urlConnection];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfiguration.timeoutIntervalForRequest = 30;
    sessionConfiguration.timeoutIntervalForResource = 60;

    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        __block NSError *jsonError;
        NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *) response;

        if(!error) {
            if(urlResponse.statusCode == 200) {
                NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&jsonError];

                if(response) {
                NSString *resp = [NSString stringWithFormat:@"%@", [dataResponse objectForKey:@"resp"]];
                if([resp isEqualToString:@"1"]) {
                    _json = [dataResponse objectForKey:@"data"];
                    [_arrServiciosTmp addObjectsFromArray:(NSArray *)_json];
                } else {
                    NSString *message = [dataResponse objectForKey:@"description"];
                }
            } else {
                self.lblMensaje.text = @"Ha ocurrido un error al obtener la información, por favor, vuelva a intentarlo en unos momentos.";
            }
            } else {
                completion(nil);
            }
        } else {
            NSLog(@"Error en Task");
        }                            
    });

And the function [self getListaProfesionalesPorLocal: [Local objectForKey: @ "idLocal"]]; is similar but obtains other information

The problem is that the app calls this function [self setFormularioConsultaCompleto]; (changing the view) but the above functions still do not quite get all the data from webservice.

Sorry for this, but I gave up, I hope can help me!

Thanks!

AUbilla
  • 19
  • 6
  • [`dispatch_sync`](https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/doc/uid/TP40008079-CH2-SW17) blocks until the block is complete. What is the problem you are having with the above code? – Rich Apr 24 '14 at 01:19
  • The problem is that one does not get the dispatch data from the web service (json) and proceeds to dispatch 2 and the same, dispatch 2 does not get all the details and hit the web service Disptach 3 and make the change of view without data. I need to get all the data and then make the change of view is understood? – AUbilla Apr 24 '14 at 01:28
  • Ah now I see - check out my [answer](http://stackoverflow.com/a/23034481/849645) for a similar issue. I'll post an answer with an example too :) – Rich Apr 24 '14 at 01:30
  • Thanks, but do not understand how I can implement something similar in my code, withCompletionBlock :( – AUbilla Apr 24 '14 at 01:36
  • Can you post the context (ie the method it is in and what `queue` is) to your question please :) – Rich Apr 24 '14 at 01:49
  • the queue is: dispatch_queue_t queue = dispatch_queue_create("threadServicios", DISPATCH_QUEUE_SERIAL); – AUbilla Apr 24 '14 at 01:59
  • In the question please - and more detail, like the whole method this is all in! – Rich Apr 24 '14 at 02:00
  • Now, sorry my mistake. – AUbilla Apr 24 '14 at 02:10

1 Answers1

0

The below uses dispatch groups to hold off starting another block till the groups work has been completed.

First change your data methods to not be wrapped in dispatch_async and accept a completion block, calling that at the end of the NSURLSessionDataTasks completionHandler:

-(void)getListaServiciosPorLocal:(id)whatEver withCompletionBlock:(dispatch_block_t)block
{
    NSURL *url = [NSURL URLWithString:urlConnection];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfiguration.timeoutIntervalForRequest = 30;
    sessionConfiguration.timeoutIntervalForResource = 60;

    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        __block NSError *jsonError;
        NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *) response;

        if(!error) {
            if(urlResponse.statusCode == 200) {
                NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&jsonError];

                if(response) {
                    NSString *resp = [NSString stringWithFormat:@"%@", [dataResponse objectForKey:@"resp"]];
                    if([resp isEqualToString:@"1"]) {
                        _json = [dataResponse objectForKey:@"data"];
                        [_arrServiciosTmp addObjectsFromArray:(NSArray *)_json];
                    } else {
                        NSString *message = [dataResponse objectForKey:@"description"];
                    }
                } else {
                    self.lblMensaje.text = @"Ha ocurrido un error al obtener la información, por favor, vuelva a intentarlo en unos momentos.";
                }
            } else {
                completion(nil);
            }
        } else {
            NSLog(@"Error en Task");
        }  
        block();  // Notify completion block                        
    });
}

Now when you call these methods:

dispatch_group_t group = dispatch_group_create();

dispatch_async(queue, ^(void) {

    NSLog(@"llego a buscar servicios por local");
    for (NSDictionary *local in _arrLocalesTmp) {
        dispatch_group_enter(group);
        [self getListaServiciosPorLocal:[local objectForKey:@"idLocal"] withCompletionBlock:^{
            dispatch_group_leave(group);
        }];
    }

    NSLog(@"llego a buscar profesionales por local");
    for (NSDictionary *local in _arrLocalesTmp) {
        dispatch_group_enter(group);
        [self getListaProfesionalesPorLocal:[local objectForKey:@"idLocal"] withCompletionBlock:^{
            dispatch_group_leave(group);
        }];
    }
});    

dispatch_group_notify(group, dispatch_get_main_queue(),^{

    [self setFormularioConsultaCompleto];
});

(Adapted from this answer)

Community
  • 1
  • 1
Rich
  • 8,108
  • 5
  • 46
  • 59
  • The block would be called CompletionBlock within each cycle for?, Does not affect anything? – AUbilla Apr 24 '14 at 02:26
  • Nope - I've had to guess the your method signatures, so unless you're doing anything odd there or just after should be fine. – Rich Apr 24 '14 at 02:29
  • Ok, I'll try, hopefully it appears, the only thing different that I have (a little strange) is that the function that makes the connection to the web service is in another class (another file). – AUbilla Apr 24 '14 at 02:32
  • Hi, I modified the code, but now the function [self setFormularioConsultaCompleto]; is not called and does the view change :S – AUbilla Apr 24 '14 at 02:45
  • Sorry, my mistake, I have one dispatch_group_enter(group); at the top extra. Now change view controller, but still have data empty :( I really understand :( – AUbilla Apr 24 '14 at 02:58