AFNetworking и асинхронные данные внутри блока

Мой код:

-(void)addressLocation:(NSArray *)inputData {
NSString *plusAddress = [[inputData objectAtIndex:0] stringByReplacingOccurrencesOfString:@" " withString:@"+"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@,%@&sensor=false&region=pl", plusAddress, [inputData objectAtIndex:1]]];

__block CLLocationCoordinate2D newRecord;
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
    NSArray *results = [JSON valueForKey:@"results"];
    NSNumber *latNumber = [[results objectAtIndex:0] valueForKeyPath:@"geometry.location.lat"];
    NSNumber *lngNumber = [[results objectAtIndex:0] valueForKeyPath:@"geometry.location.lng"];
    CGFloat lat = [latNumber floatValue];
    CGFloat lng = [lngNumber floatValue];
    newRecord = CLLocationCoordinate2DMake(lat, lng);
}  failure:nil];
[operation start];
[operation waitUntilFinished];

KantorPoint *newPoint = [[KantorPoint alloc] init];
newPoint.coordinate = newRecord;
newPoint.name = [inputData objectAtIndex:1];
newPoint.address = [inputData objectAtIndex:0];
[self.pointersArray addObject:newPoint];
}

Я пытаюсь передать newRecord из операционного блока, как в этом ответе. Но newPoint.coordinate это null и я не могу сделать что-то вроде return newRecord внутри блока (получить ошибку). Есть ли способ решить эту проблему?


person RomanHouse    schedule 08.07.2012    source источник
comment
Бьюсь об заклад, вы получаете какую-то ошибку в своем запросе JSON. Вы не передаете блок failure при создании operation. Сделайте это и посмотрите, вызовут ли его.   -  person Nate    schedule 08.07.2012
comment
мой запрос JSON в порядке. если внутри блока я делаю NSLog(@"newRecord lat = %f",newRecord.latitude); консоль показывает мне правильное значение.   -  person RomanHouse    schedule 08.07.2012
comment
Хм. Просто любопытно. Почему вы используете асинхронный запрос, если хотите дождаться его завершения (по сути, делая его синхронным)? Код, который вы разместили, упрощен для того, чтобы задать вопрос?   -  person Nate    schedule 08.07.2012
comment
AFJSONRequestOperation имеет внутреннюю очередь обработки, я думаю, проблема в том, что блок успеха вызывается после завершения обработки json, что происходит после завершения самой операции.   -  person Felix    schedule 08.07.2012
comment
@ Нейт, хм, ты прав. но есть ли способ сделать синхронный запрос таким хорошим, как AF?   -  person RomanHouse    schedule 08.07.2012


Ответы (1)


Я не уверен в вашей цели, но я бы переписал код таким образом.

- (void)addressLocation:(NSArray *)inputData {

    NSString *plusAddress = [[inputData objectAtIndex:0] stringByReplacingOccurrencesOfString:@" " withString:@"+"];
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@,%@&sensor=false&region=pl", plusAddress, [inputData objectAtIndex:1]]];

    __block YourClass *selfBlock = self; // __weak YourClass *selfBlock = self; if you use ARC

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

        NSArray *results = [JSON valueForKey:@"results"];
        NSNumber *latNumber = [[results objectAtIndex:0] valueForKeyPath:@"geometry.location.lat"];
        NSNumber *lngNumber = [[results objectAtIndex:0] valueForKeyPath:@"geometry.location.lng"];
        CGFloat lat = [latNumber floatValue];
        CGFloat lng = [lngNumber floatValue];
        CLLocationCoordinate2D newRecord = CLLocationCoordinate2DMake(lat, lng);

        KantorPoint *newPoint = [[KantorPoint alloc] init];
        newPoint.coordinate = newRecord;
        newPoint.name = [inputData objectAtIndex:1];
        newPoint.address = [inputData objectAtIndex:0];
        [selfBlock.pointersArray addObject:newPoint];

    }  failure:nil];

    // the queue needs to be allocated somewhere...
    [[self operationQueue] addOperation:operation];
}

Обратите внимание, если вы используете ARC: __block не препятствует сохранению объекта. Вместо этого используйте __weak.

Изменить

Согласно phix23, вам нужно где-то сохранить свою работу. Таким образом, простой способ сделать это — создать свойство типа NSOperationQueue и добавить операцию в эту очередь. Когда вы добавляете его в очередь, вам не нужно выполнять start операцию.

Надеюсь, это поможет.

person Lorenzo B    schedule 08.07.2012
comment
операция ДОЛЖНА быть где-то сохранена, иначе она будет освобождена. Я бы использовал очередь операций, которая является членом класса. - person Felix; 08.07.2012
comment
@phix23 О да! он мог бы добавить эту операцию в NSOperationQueue. Может быть, я могу изменить свой ответ, чтобы приспособить его. Спасибо. - person Lorenzo B; 08.07.2012
comment
Это будет работать, но таким образом addObject до pointersArray будет в фоновом потоке, вместо этого я хочу, чтобы это было в основном потоке. - person RomanHouse; 08.07.2012
comment
@RomanHouse Почему? Если операция создается в основном потоке, обработчик завершения будет выполняться в этом потоке. Напротив, механизм загрузки выполняется в фоновом потоке. Вы также можете проверить это с помощью BOOL isMainThread = [NSThread isMainThread]. - person Lorenzo B; 08.07.2012
comment
@ phix23 Я изменил свой ответ на основе вашего комментария. Спасибо. - person Lorenzo B; 08.07.2012