异步块返回问题

时间:2017-09-10 11:38:16

标签: objective-c multithreading asynchronous block

使用此处的函数从异步块返回值(只是数据库查询)。问题是应用程序冻结并因内存问题而终止。寻求建议是否最好在主线程上运行它还是应该避免这种情况?请注意,它正在另一个线程上执行。

- (NSString *)databaseQuery:(NSString*)ingredient {
    __block NSString *valueType = nil;
    __block BOOL done = NO;
    [[[_ref child:@"ingredients"] queryEqualToValue:valueType childKey:ingredient] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
        for (FIRDataSnapshot *child in snapshot.children) {
            valueType = child.value;
        }
        done = YES;
    } withCancelBlock:^(NSError * _Nonnull error) {
        NSLog(@"%@", error.localizedDescription);
        done = YES;
    }];

    while (!done) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
    }
    return valueType;
}

更新1:尝试使用以下代码并产生相同的结果。

- (NSString *)databaseQuery:(NSString*)ingredient {
    __block NSString *valueType = nil;
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    FIRDatabaseQuery *query = [[_ref child:@"ingredients"] queryEqualToValue:valueType childKey:ingredient] ;
    [query observeEventType:FIRDataEventTypeChildAdded
                  withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
                      valueType = snapshot.value;
                      dispatch_semaphore_signal(sem);
                  }
            withCancelBlock:^(NSError * _Nonnull error) {
                NSLog(@"%@", error.localizedDescription);
                dispatch_semaphore_signal(sem);
            }];

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    return valueType;
}

更新2:

更改了格式,因此函数不会从块返回。它只返回FIRDatabaseQuery。

- (FIRDatabaseQuery *)databaseQuery:(NSString*)ingredient {
    __block NSString *valueType = nil;
    FIRDatabaseQuery *query = [[_ref child:@"ingredients"] queryEqualToValue:valueType childKey:ingredient];
    return query;
}

以下部分是另一个程序。除了返回的值为null。

query = [self databaseQuery:substring];
            [query observeEventType:FIRDataEventTypeChildAdded
                          withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
                              idValue = snapshot.value;
                          }
                    withCancelBlock:^(NSError * _Nonnull error) {
                        NSLog(@"%@", error.localizedDescription);
                    }];
            NSLog(@"%@", idValue);

1 个答案:

答案 0 :(得分:0)

解决:尽管我想避免使用NSRunLoop,但问题是我已经运行了一个并且我没有停止它。

答案是将CFRunLoopStop(CFRunLoopGetCurrent());添加到应用程序中。应该使用信号量替换它。

问题是,这是一个循环。搜索完第一个项目后,它会卡住并再次挂起。为了解决这个问题,我按照建议使用了调度组。

注意:在循环之前声明调度组以及idValue。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
                dispatch_group_enter(_groupSearch);
                dispatch_async(queue, ^{
                [[self databaseQuery:searchItem] observeEventType:FIRDataEventTypeChildAdded
                              withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
                                  idValue = snapshot.value;
                                  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, ^{
                        if (idValue != NULL) {
                            NSLog(@"%@",idValue);
                        }
                    });
                });