主线程冲突/计时问题 - GCD - iPhone

时间:2011-12-17 08:20:50

标签: iphone objective-c multithreading thread-safety grand-central-dispatch

我有以下调度队列我的应用程序:

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方法更新UI进度视图:

- (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已经被释放,因此当app3DTidyUpProgresUpdate方法请求访问类中的变量时,应用程序崩溃了dealloced。

有人可以就如何解决这个时间问题提出建议吗?

提前谢谢。

3 个答案:

答案 0 :(得分:3)

只是想一想 - 尝试在调度中重命名变量:

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

答案 1 :(得分:0)

使用两种不同的机制在主线程中调度任务:dispatch_asyc和performSelectorInMainThread:withObject:waitUntilDone:。每个机制都使用自己的队列,由主运行循环读取。

未定义读取这些队列的顺序。因此,performSelectorInMainThread:withObject:waitUntilDone调度的任务可以在使用dispatch_async调度的任务之后(或之前)执行,无论先调度哪个任务。

您应该更新tidyUpProgress:使用dispatch_async。然后订单将得到保证。

此外,在释放对象后,应始终使保存对该对象的引用的变量无效。

答案 2 :(得分:-3)

  • 这是错误的方式:

    float arrayCount = [pointerStorageArray count];

- 正确方式:

NSUinteger  arrayCountInt = [pointerStorageArray count]; 
NSNumber *arrayCountNumber = [NSNumber numberWithUnsignedInteger:arrayCountInt]
float arrayCount = [arrayCountNumber floatValue];