Как безопасно заблокировать переменную с помощью GCD?

#cocoa #concurrency #grand-central-dispatch

#cocoa #параллелизм #grand-central-dispatch

Вопрос:

У меня есть NSMutableArray, в который мне нужно добавить объекты из нескольких отправленных мной блоков. Является ли это приемлемым способом убедиться, что массив безопасно изменяется? Они уже отправляются изнутри и NSOperation и выполняются в фоновом режиме. Я загружал данные из этого потока последовательно, но загрузка списка местоположений сразу становилась очень медленной.

 NSMutableArray *weatherObjects = [[NSMutableArray alloc] init];
ForecastDownloader *forecastDownloader = [[ForecastDownloader alloc] init];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_queue_t serialQueue;
serialQueue = dispatch_queue_create("us.mattshepherd.ForecasterSerialQueue", NULL);

for (NSDictionary *theLocation in self.weatherLocations) {

    // Add a task to the group
    dispatch_group_async(group, queue, ^{
        NSLog(@"dispatching...");
        int i = 0;
        WeatherObject *weatherObject = [forecastDownloader getForecast:[theLocation objectForKey:@"lat"] lng:[theLocation objectForKey:@"lng"] weatherID:[[theLocation objectForKey:@"id"] intValue]];

        }
        if(!weatherObject){
            //need to implement delegate method to show problem updating weather
            NSLog(@"problem updating weather data");
        }else{
            NSLog(@"got weather for location...");
            dispatch_sync(serialQueue, ^{
                [weatherObjects addObject:weatherObject];
            });


        }
    });

}
// wait on the group to block the current thread.
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

NSLog(@"finished getting weather for all locations...");
//we will now do something with the weatherObjects
 

Ответ №1:

Это не сработает, потому что вы каждый раз создаете новую блокировку, а не используете одну блокировку для переменной (аналогия: представьте запертую дверь в комнату. Если у каждого будет своя дверь с замком, вряд ли имеет значение, что они ее запирают, поскольку все остальные войдут в свою дверь).

Вы можете либо использовать один NSLock для всех итераций, либо (что практически эквивалентно) одну очередь последовательной отправки.

Комментарии:

1. Да, это выглядит нормально. Не забудьте dispatch_release последовательную очередь, если вы не используете ARC.