调度队列如何工作

时间:2012-04-11 15:57:02

标签: objective-c grand-central-dispatch

我在这里有点困惑,我使用队列,我到了一点,我有点迷失。

我有一个名为getPeople的方法,他必须从服务器上获取用户的图片。为了不阻止我使用的应用程序:

 -(IBAction)seeMorePeople{
        dispatch_queue_t getPeopleQueue = dispatch_queue_create("Pinta Ocupantes", NULL);
        dispatch_async(getPeopleQueue, ^{
           [self getPeople];
        });
       dispatch_release(getPeopleQueue);
 }

每次用户点击按钮时都会执行上一个代码。像“从这张专辑给我照片”然后另一个点击“现在我想要来自其他专辑的人物照片”,不同的照片和不同数量的照片。如果用户非常快地点击按钮,则第一个队列在第二个队列已经启动时不会完成获取数据。在getPeople中,我将数据存储在NSMutableArray中,因此当两个队列同时执行时,两个队列都在同一个数组上写入,并且应用程序因超出范围异常而崩溃。 getPeople遍历数据的方式是这样的:

-(void)getPeople:(NSDictionary *)peopleDictionary{
    //I receive an NSDictionary and I go through it
    NSArray *keys = [peopleDictionary allKeys];
    int indexOfArray = 0;
    for(NSString *key in keys){
         //Complex operation that are not important
         [peopleInArray insertObjetAtIndex:indexOfArray];//People in array is a global variable
         indexOfArray++;
    }
}

我无法弄清楚如何摆脱这种情况,我想在第二个队列进入时停止第一个队列,但是GCD没有这个选项...任何其他方式来完成这个,希望没有重大的重新编码,无论如何我现在没有想法,所以任何线索都会有所帮助。

3 个答案:

答案 0 :(得分:8)

如果可能的话,我建议您避免与信号量同步。 GCD的设计是为了避免这种情况。后台任务应该准备数据但不要触摸外部状态。准备好数据时,它应该将外部状态的更新分配给一个串行队列,或者,如果状态是绑定到GUI,则分配给主队列。

所以,像这样:

-(void)getPeople:(NSDictionary *)peopleDictionary{
    //I receive an NSDictionary and I go through it
    NSArray *keys = [peopleDictionary allKeys];
    for(NSString *key in keys){
         //Complex operation that are not important
         dispatch_async(dispatch_get_main_queue(), ^{
             [peopleInArray addObject:<whatever>];
         });
    }
}

如果您想要替换数组,而不是以交错方式添加两个线程,则需要在后台累积整个数组,并将整个peopleInArray设置为主队列。

如果您想要取消,可以使用旗帜自行实施,或者您应该考虑使用NSOperationNSOperationQueue代替GCD。虽然您的自定义操作仍然需要检查它们是否已被取消并停止工作,但它们具有内置取消的概念。

答案 1 :(得分:2)

你是对的,没有办法阻止派遣的队列。您可以做的一件事是确保只有一个队列同时访问getPeople semaphoresthis might be even more interesting)。

如果您只是想避免用户多次点击该按钮,您可以使用在异步调度中设置为stillExecuting的bool变量YES并设置为NO at getPeople的结尾。在创建getPeopleQueue之前,您只需检查getPeople是否仍在执行。

if(!stillExecuting) {
       dispatch_queue_t getPeopleQueue = dispatch_queue_create("Pinta Ocupantes", NULL);
        dispatch_async(getPeopleQueue, ^{
           [self getPeople];
        });
       dispatch_release(getPeopleQueue);
}

答案 2 :(得分:0)

NSString * lastLoginTime = @“您的上次登录时间”;

    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
    [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate* date1 = [dateFormat lastLoginTime];
    NSDate* date2 = [dateFormat dateFromString:[NSString currentDateTime]];
    NSTimeInterval secondsSinceLastLogin = [date2 timeIntervalSinceDate:date1];
    //  NSLog(@"Seconds Since Last Login: %g", secondsSinceLastLogin);
    int hours = (int)secondsSinceLastLogin / 3600;