Проблемы с отправкой iOS

Я новичок в iOS, и у меня есть проблемы с пониманием и применением хорошей диспетчеризации ... У меня есть приложение, мне нужно запросить веб-сайт (api) в цикле for, конец этого цикла мне нужно сделать дополнительные запросы в другом цикле , и, наконец, по окончании обоих циклов нужно переключать взгляды.

Теперь у меня есть этот код (после долгих проб и ошибок, но все еще не работает):

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];
        }
    });

Функция [self getListaServiciosPorLocal: [Local objectForKey: @"idLocal"]]; составляет:

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");
        }                            
    });

И функция [self getListaProfesionalesPorLocal: [Local objectForKey: @"idLocal"]]; похож, но получает другую информацию

Проблема в том, что приложение вызывает эту функцию [self setFormularioConsultaCompleto]; (изменение вида), но вышеперечисленные функции по-прежнему не совсем получают все данные из веб-сервиса.

Извините за это, но я сдался, надеюсь, вы мне поможете!

Спасибо!


person AUbilla    schedule 24.04.2014    source источник
comment
dispatch_sync блокирует до тех пор, пока блок не будет завершен. В чем проблема с приведенным выше кодом?   -  person Rich    schedule 24.04.2014
comment
Проблема в том, что вы не получаете данные отправки от веб-службы (json) и переходите к отправке 2 и тому же, отправка 2 не получает всех деталей и попадает в веб-службу Disptach 3 и делает изменение вида без данных . Мне нужно получить все данные, а затем изменить представление, понятно?   -  person AUbilla    schedule 24.04.2014
comment
А, теперь я вижу - посмотрите мой ответ на аналогичную проблему. Я тоже отправлю ответ с примером :)   -  person Rich    schedule 24.04.2014
comment
Спасибо, но не понимаю, как я могу реализовать что-то подобное в своем коде, с CompletionBlock :(   -  person AUbilla    schedule 24.04.2014
comment
Можете ли вы опубликовать контекст (то есть метод, в котором он находится, и что такое queue) на ваш вопрос, пожалуйста :)   -  person Rich    schedule 24.04.2014
comment
очередь: dispatch_queue_t queue = dispatch_queue_create(threadServicios, DISPATCH_QUEUE_SERIAL);   -  person AUbilla    schedule 24.04.2014
comment
В вопросе пожалуйста - и поподробнее, вроде весь метод в этом весь!   -  person Rich    schedule 24.04.2014
comment
Теперь извините за мою ошибку.   -  person AUbilla    schedule 24.04.2014
comment
Спасибо - я обновил свой ответ   -  person Rich    schedule 24.04.2014


Ответы (1)


В приведенном ниже примере группы диспетчеризации используются для задержки запуска следующего блока до тех пор, пока работа групп не будет завершена.

Сначала измените свои методы данных, чтобы они не были обернуты в dispatch_async, и примите блок завершения, вызвав его в конце 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                        
    });
}

Теперь, когда вы вызываете эти методы:

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];
});

(Адаптировано из этого ответа)

person Rich    schedule 24.04.2014
comment
Блок будет называться CompletionBlock внутри каждого цикла for?, ни на что не влияет? - person AUbilla; 24.04.2014
comment
Нет - мне пришлось угадать сигнатуры ваших методов, поэтому, если вы не делаете ничего странного там или сразу после этого, все должно быть в порядке. - person Rich; 24.04.2014
comment
Хорошо, я попробую, надеюсь, это появится, единственное, что у меня отличается (немного странно), это то, что функция, которая делает подключение к веб-сервису, находится в другом классе (другом файле). - person AUbilla; 24.04.2014
comment
Привет, я изменил код, но теперь функция [self setFormularioConsultaCompleto]; не вызывается и вид меняется: S - person AUbilla; 24.04.2014
comment
Извините, моя ошибка, у меня есть один dispatch_group_enter(group); в верхней доп. Теперь измените контроллер представления, но данные все еще пусты :( Я действительно понимаю :( - person AUbilla; 24.04.2014