Переменная блока получает значение null вне блока - xcode

Я пытаюсь перенести блочную переменную и поместить ее в мой удобный инициализатор, но переменная возвращает значение null, может ли кто-нибудь показать мне правильный способ сделать это, спасибо, также проверьте, правильно ли я выполнил свой результат NSComparison, вот код,

- (void) retrieveData
{
NSURL *url = [NSURL URLWithString:jsonFile];
NSData *data = [NSData dataWithContentsOfURL:url];

_jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

_salesArray = [[NSMutableArray alloc]init];

for (int i = 0; i < _jsonArray.count; i++) {

    NSString *sID = [[_jsonArray objectAtIndex:i] objectForKey:@"id"];
    NSString *sName = [[_jsonArray objectAtIndex:i] objectForKey:@"name"];
    NSString *sAddress = [[_jsonArray objectAtIndex:i] objectForKey:@"address"];
    NSString *sPostcode = [[_jsonArray objectAtIndex:i] objectForKey:@"postcode"];


    __block NSString *distance;
    CLGeocoder *geocoder = [[CLGeocoder alloc]init];
    [geocoder geocodeAddressString:sPostcode completionHandler:^(NSArray *placemarks,   NSError *error) {


        if (error == nil && placemarks.count > 0) {

            CLPlacemark *placemark = [placemarks objectAtIndex:0];


            CLLocation *location = placemark.location;
            CLLocation *myLocation = self.manager.location;
            CLLocationDistance miles =  [location distanceFromLocation:myLocation];
            //this is the variable i want in my convenience init.
            distance = [NSString stringWithFormat:@"%.1f m", (miles/1609.344)];

        }

    }];

    [_salesArray addObject:[[sales alloc] initWithSales:sID andName:sName andAddress:sAddress andPostcode:distance]];

}

[_salesArray sortUsingComparator:
 ^NSComparisonResult(id obj1, id obj2){

     sales *p1 = (sales *)obj1;
     sales *p2 = (sales *)obj2;
     if (p1.postcode > p2.postcode) {
         return (NSComparisonResult)NSOrderedDescending;
     }

     if (p1.postcode < p2.postcode) {
         return (NSComparisonResult)NSOrderedAscending;
     }
     return (NSComparisonResult)NSOrderedSame;
 }
 ];

[self.tableView reloadData];

}

Заранее спасибо всем, кто может помочь, это последняя часть моего приложения до завершения :)


person silly_cone    schedule 18.07.2014    source источник
comment
Этот вопрос задают много. Вот пример. stackoverflow.com/questions/24870458/   -  person CrimsonChris    schedule 21.07.2014


Ответы (2)


-[CLGeocoder geocodeAddressString:completionHandler:] запускает обработчик завершения асинхронно, и он не запустит блок до завершения остальной части этой функции. distance не "получает значение null"; скорее, он еще не установлен.

person newacct    schedule 18.07.2014
comment
вы правы, расстояние не становится нулевым внутри блока, но когда я вставляю расстояние в мой инициализатор _salesArray [[sales alloc]], который находится за пределами блока, он получает нуль, как это обойти? - person silly_cone; 19.07.2014
comment
@silly_cone: Как я уже сказал, он не становится нулевым, он просто еще не установлен. Основная проблема заключается в том, что это асинхронная операция, поэтому вы никак не можете получить ее в это время. Вам нужно изменить свой рабочий процесс, чтобы вы могли добавить объект в salesArray позже, в блоке завершения. - person newacct; 19.07.2014
comment
не могли бы вы привести пример, пожалуйста, я действительно борюсь с этим, спасибо. - person silly_cone; 19.07.2014

ваш блок запускается ПОСЛЕ завершения функции ... не имеет значения, находится ли «строка кода» после или до блока.

решение состоит в том, чтобы заблокировать вызов функции «продолжения»:

например вместо - (void) retrieveData
есть - (void) beginRetrieveData, который вызывает блок, а затем есть - (void) finishRetrieveData, который вызывается блоком и не запускается перед блоком ;)


вот как может выглядеть ваш код:

- (void) beginRetrieveData
{
    NSURL *url = [NSURL URLWithString:jsonFile];
    NSData *data = [NSData dataWithContentsOfURL:url];

    _jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

    _salesArray = [[NSMutableArray alloc]init];

    for (int i = 0; i < _jsonArray.count; i++) {

        NSString *sID = [[_jsonArray objectAtIndex:i] objectForKey:@"id"];
        NSString *sName = [[_jsonArray objectAtIndex:i] objectForKey:@"name"];
        NSString *sAddress = [[_jsonArray objectAtIndex:i] objectForKey:@"address"];
        NSString *sPostcode = [[_jsonArray objectAtIndex:i] objectForKey:@"postcode"];


        CLGeocoder *geocoder = [[CLGeocoder alloc]init];
        [geocoder geocodeAddressString:sPostcode completionHandler:^(NSArray *placemarks,   NSError *error) {


            if (error == nil && placemarks.count > 0) {

                CLPlacemark *placemark = [placemarks objectAtIndex:0];


                CLLocation *location = placemark.location;
                CLLocation *myLocation = self.manager.location;
                CLLocationDistance miles =  [location distanceFromLocation:myLocation];
                //this is the variable i want in my convenience init.
                NSString *distance = [NSString stringWithFormat:@"%.1f m", (miles/1609.344)];
                [self finishRetrieveData:distance]; //continue
            }

        }];
    }
}

- (void) finishRetrieveData:(NSString*)distance
{
    [_salesArray addObject:[[sales alloc] initWithSales:sID andName:sName andAddress:sAddress andPostcode:distance]];
}
person Daij-Djan    schedule 18.07.2014
comment
Это работает, но после того, как я обновляю представление таблицы несколько раз, оно падает и выдает эту ошибку: Завершение приложения из-за необработанного исключения «NSRangeException», причина: «*** - [__NSArrayM objectAtIndex:]: индекс 4 за пределами для пустого массива» это потому, что у меня есть [self.tableview reloadData] в качестве последней строки метода finishRetrieveData - person silly_cone; 19.07.2014
comment
нет, это было бы хорошо. я не могу сказать, что не так в вашем коде --- я также не вижу ничего плохого в коде выше - person Daij-Djan; 19.07.2014