Search code examples
iosdispatch

Problems with dispatch iOS


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!


Solution

  • 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)