等待代码执行(已使用调度组)

Waiting for code to execute (already used dispatch groups)

得到下面显示的这段冗长的代码,但我遇到了困难。基本上,代码运行完美,并且完全按照我的意愿执行。但是,它需要在最后打印 "Finished" 之前完成本节中的所有代码 运行。但是,添加信号量或另一个调度组会强制设置断点。可能很明显,但是有人可以给我一些建议吗?

注意:我不能使用底部的调度来调用另一个方法。记住它在一个循环中。

for (id i in arr) {
    searchByName = nil;
    if ([i containsString:@"word1"] || [i containsString:@"word2"]) {
        NSRange searchFromRange = [i rangeOfString:@"ong>"];
        NSRange searchToRange = [i rangeOfString:@"</str"];
        NSString *substring = [i substringWithRange:NSMakeRange(searchFromRange.location+searchFromRange.length, searchToRange.location-searchFromRange.location-searchFromRange.length)];
        [allergens addObject:substring];
        if ([substring isEqualToString:@"Examee"] && veg_lac_ovoSafe == TRUE) {
            veg_ovoSafe = FALSE;
            vegSafe = FALSE;
        }
        else if ([substring isEqualToString:@"Example"] && veg_lac_ovoSafe == TRUE) { //USE OF HEURISTICS
            veg_lacSafe = FALSE;
            vegSafe = FALSE;
        }
        else if ([substring isEqualToString:@"Exam"]) {
            pescetarianSafe = TRUE;
            vegSafe = FALSE;
            veg_ovoSafe = FALSE;
            veg_lacSafe = FALSE;
            veg_lac_ovoSafe = FALSE;
            pollotarianSafe = FALSE;
        }
        NSCharacterSet *charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
        NSCharacterSet *numbersToRemove = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
        substring = [[substring componentsSeparatedByCharactersInSet:charactersToRemove] componentsJoinedByString:@""];
        searchByName = [[[substring componentsSeparatedByCharactersInSet:numbersToRemove] componentsJoinedByString:@""] lowercaseString];
    }
    else {
        NSCharacterSet *charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
        NSCharacterSet *numbersToRemove = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
        NSString *searchItem = [[i componentsSeparatedByCharactersInSet:charactersToRemove] componentsJoinedByString:@""];
        searchByName = [[[searchItem componentsSeparatedByCharactersInSet:numbersToRemove] componentsJoinedByString:@""] lowercaseString];
    }
    if (![searchByName isEqualToString:@" "]) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
        dispatch_group_enter(_groupSearch);
        dispatch_async(queue, ^{
            [[self databaseQuery:searchByName] observeEventType:FIRDataEventTypeChildAdded
                                                      withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
                if (snapshot.value != NULL) {
                    NSLog(@"%@", snapshot.value);
                    for (int i=0; i < [[NSString stringWithFormat:@"%@", snapshot.value] length]; i++) {
                        NSString *x  = [NSString stringWithFormat:@"%c", [[NSString stringWithFormat:@"%@", snapshot.value] characterAtIndex:i]];
                        NSLog(@"%@", x);
                        if ([x isEqualToString:@"1"]) {
                            vegSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"2"]) {
                            vegSafe = FALSE;
                            veg_lacSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"3"]) {
                            vegSafe = FALSE;
                            veg_ovoSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"4"]) { //Could use switch case.
                            vegSafe = FALSE;
                            veg_lac_ovoSafe = FALSE;
                            veg_lacSafe = FALSE;
                            veg_ovoSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"5"]) {
                            pescetarianSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"6"]) {
                            pollotarianSafe = FALSE;
                        }
                    }
                }

                dispatch_group_leave(_groupSearch);
            }
                                                withCancelBlock:^(NSError * _Nonnull error) {
                NSLog(@"%@", error.localizedDescription);
                dispatch_group_leave(_groupSearch);
            }];
        });
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            dispatch_group_wait(_groupSearch, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));
            dispatch_sync(queue, ^{
                //Hi
            });
        });
    }
}

NSLog(@"Finished");

您对 dispatch_group_wait 的使用是在错误的地方。它需要在 for 循环之后,而不是在循环内部。您可以在循环之前创建 queue 并根据需要重用它。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

for (id i in arr) {
    searchByName = nil;

    // Lots of other code here

    if (![searchByName isEqualToString:@" "]) {
        dispatch_group_enter(_groupSearch);
        dispatch_async(queue, ^{
            [[self databaseQuery:searchByName] observeEventType:FIRDataEventTypeChildAdded withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
                if (snapshot.value != NULL) {
                    NSLog(@"%@", snapshot.value);
                    for (int i=0; i < [[NSString stringWithFormat:@"%@", snapshot.value] length]; i++) {
                        NSString *x  = [NSString stringWithFormat:@"%c", [[NSString stringWithFormat:@"%@", snapshot.value] characterAtIndex:i]];
                        NSLog(@"%@", x);
                        if ([x isEqualToString:@"1"]) {
                            vegSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"2"]) {
                            vegSafe = FALSE;
                            veg_lacSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"3"]) {
                            vegSafe = FALSE;
                            veg_ovoSafe = FALSE;

                        }
                        else if ([x isEqualToString:@"4"]) { //Could use switch case.
                            vegSafe = FALSE;
                            veg_lac_ovoSafe = FALSE;
                            veg_lacSafe = FALSE;
                            veg_ovoSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"5"]) {
                            pescetarianSafe = FALSE;
                        }
                        else if ([x isEqualToString:@"6"]) {
                            pollotarianSafe = FALSE;
                        }
                    }
                }
                dispatch_group_leave(_groupSearch);
            }
            withCancelBlock:^(NSError * _Nonnull error) {
                NSLog(@"%@", error.localizedDescription);
                dispatch_group_leave(_groupSearch);
            }];

        });
    }
}

dispatch_group_wait(_groupSearch, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)));

NSLog(@"Finished");

由于您在 dispatch_async() 块内调用 dispatch_group_wait(),您似乎希望 运行 在全局调度队列上异步完成块。正确的方法是使用 dispatch_group_notify() 代替:

dispatch_group_notify(groupSearch, queue, ^{
    NSLog(@"Finished")
});

一旦提交给该组的所有块都完成,这将 运行 指定队列上的块,因此不需要 dispatch_async()dispatch_sync()。此外,在 dispatch_async() 内等待会阻塞 GCD 池中的一个线程,这是一个非常糟糕的主意,因为它们的数量是有限的。这也是使用 dispatch_group_notify() 可以避免的事情。

编辑:以下段落与您更新后的代码不再相关:

此外,正如另一个回答者指出的那样,您可能希望在循环结束后将调用置于 dispatch_group_notify(),假设您想要一个完成块到 运行在你工作的最后。如果您实际上想要的是一大堆单独的通知,循环中每个 运行 一个通知,那么您可能应该在循环中创建一个新组并使用它。对整个 shebang 使用一个组,然后在循环中设置通知将导致每个通知不仅等待 dispatch_group_leave() 通过循环调用特定 运行,而且等待 allany 运行 上通过循环进行的 dispatch_group_enter() 调用将被平衡。因此,在完成所有工作之前你什么也得不到,然后你会突然一次性发送一大堆完成块,伴随着线程爆炸,因为它们都将提交到全局队列中。这可能不是你想要的。