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

时间:2017-09-11 19:27:00

标签: objective-c block dispatch-async

下面显示了这段冗长的代码,我碰到了一堵砖墙。基本上代码运行完美,完全符合我的要求。但是,它需要在打印"完成"之前完成本节中的所有代码的运行。在末尾。但是,添加信号量或其他调度组会强制断点。可能很明显,但有人可以给我一些建议吗?

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

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");

2 个答案:

答案 0 :(得分:0)

由于您在dispatch_group_wait()块内调用dispatch_async(),因此您似乎希望在全局调度队列上异步运行完成块。正确的方法是使用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()调用,而且等待所有已经在任何上进行的dispatch_group_enter()次调用通过循环进行平衡。因此,在完成所有工作之前,您将什么也得不到,然后您会突然发送一大堆完成块,并伴随线程爆炸,因为它们都将在全局队列中提交。这可能不是你想要的。

答案 1 :(得分:-1)

您对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"); 并根据需要重复使用它。

{{1}}