Конфликт главной темы / проблема синхронизации - GCD - iPhone - PullRequest
1 голос
/ 17 декабря 2011

У меня есть следующая очередь отправки моего приложения:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^  {  

[activeModel freeUpMallocedData];

// UI Updates have to be made on the main thread, so request from GCD.

dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^  {  

[mainViewController removeTidyUpScreen];
[mainViewController showSceneList]; 
[activeModel release];

});
});

Метод freeUpMallocedData обновляет представление хода выполнения пользовательского интерфейса:

- (void) freeUpMallocedData {

// Calculate the percentage increase for each item in the pointerStorageArray as it is released so we can update the Progress Screen.

float arrayCount = [pointerStorageArray count];
float incrementCounter = 1 / arrayCount; // Caculates 1% of pointerStorageArray
float newValue = incrementCounter;
int stepCounter = 0;

NSString * message;

// Now iterate through the pointerStorageArray and free all malloced memory.

for (NSValue * value in pointerStorageArray) {

    stepCounter ++;
    newValue = newValue + incrementCounter;

    message = [NSString stringWithFormat:@"Freeing Up Memory (%d of %d) ...", stepCounter, (int)arrayCount];

    free(value);

    [self tidyUpProgress:message amount:newValue];

}

}

Затем метод tidyUpProgress выполняется в главном потоке.

- (void) tidyUpProgress: (NSString *) progressMsg amount: (float) amount {
if (tidyUpMonitorDelegate) {
    tidyUpProgressMsg = progressMsg;
    tidyUpProgressAmount = amount;
    [tidyUpMonitorDelegate performSelectorOnMainThread:@selector(model3DTidyUpProgressUpdate) withObject:nil waitUntilDone:NO];
}
}

- (void) model3DTidyUpProgressUpdate {
progressView.progress = app.activeModel.tidyUpProgressAmount;
loadingStatus.text = app.activeModel.tidyUpProgressMsg;
}

Проблема заключается в том, что приложение завершает работу при завершении метода freeUpMallocedData. Причина этого в том, что моя первоначальная очередь отправки переходит к запросу основной очереди, которая затем освобождает activeView. Похоже, это перехватывает поток из tidyUpMonitorDelegate до того, как он сможет выполнить свое последнее обновление - когда он возвращает основной поток, то activeView был выпущен, и поэтому приложение аварийно завершает работу, поскольку метод model3DTidyUpProgresUpdate запрашивает доступ к переменной в классе, который теперь был dealloced.

Может кто-нибудь посоветовать, как решить эту проблему с синхронизацией?

Заранее спасибо.

Ответы [ 3 ]

3 голосов
/ 17 декабря 2011

Просто мысль - попробуйте переименовать переменную внутри отправки:

dispatch_queue_t mainqueue = dispatch_get_main_queue();
dispatch_async(mainqueue, ^  {  
0 голосов
/ 17 декабря 2011

Вы используете два разных механизма для планирования задач в главном потоке: dispatch_asyc и executeSelectorInMainThread: withObject: waitUntilDone :. Каждый механизм использует свою очередь, которая читается основным циклом выполнения.

Порядок чтения этих очередей не определен. Таким образом, задача, запланированная методом executeSelectorInMainThread: withObject: waitUntilDone, может выполняться после (или до) задачи, запланированной с dispatch_async, независимо от того, какая из них была запланирована первой.

Вы должны обновить tidyUpProgress: использовать dispatch_async. Тогда заказ будет гарантирован.

Более того, после освобождения объекта вы всегда должны аннулировать переменную, которая содержит ссылку на этот объект.

0 голосов
/ 17 декабря 2011
  • это неправильный путь:

    float arrayCount = [pointerStorageArray count];

- правильный путь:

NSUinteger  arrayCountInt = [pointerStorageArray count]; 
NSNumber *arrayCountNumber = [NSNumber numberWithUnsignedInteger:arrayCountInt]
float arrayCount = [arrayCountNumber floatValue];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...