等待网络通话结束

coj*_*joj 5 concurrency objective-c grand-central-dispatch ios

我要实现的目标是发出网络请求并等待它完成,以便我可以决定下一步应该是什么应用。通常,我会避免这种解决方案,但是这种情况很少见,在这种情况下,代码库有很多遗留问题,并且我们没有足够的时间来应用必要的更改来使事情变得正确

我正在尝试编写具有以下定义的简单输入输出方法:

- (nullable id<UserPaymentCard>)validCardForLocationWithId:(ObjectId)locationId;
Run Code Online (Sandbox Code Playgroud)

事实是,为了在此方法内执行某些验证,我需要发出网络请求以仅接收必要的信息,因此我想等待此请求完成。

我想到的第一件事就是使用dispatch_semaphore_t,所以最终得到了这样的东西:

- (nullable id<UserPaymentCard>)validCardForLocationWithId:(ObjectId)locationId {
    id<LocationsReader> locationsReader = [self locationsReader];

    __block LocationStatus *status = nil;
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    [locationsReader fetchLocationProviderStatusFor:locationId completion:^(LocationStatus * _Nonnull locationStatus) {
        status = locationStatus;
        dispatch_semaphore_signal(sema);
    } failure:nil];
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

    return [self.paymentCards firstCardForStatus:status];
}
Run Code Online (Sandbox Code Playgroud)

一切都可以编译并运行,但是我的UI冻结了,实际上我从未收到sempahore的信号。因此,我开始玩dispatch_group_t完全相同的结果。

看起来我可能在执行代码的地方遇到了一些问题,但是我不知道该如何处理并获得预期的结果。当我尝试将所有内容包装起来时,dispatch_async我实际上停止了阻塞主队列,但dispatch_async立即返回,因此我return在网络请求完成之前从此方法退出。

我想念什么?如果没有一些while技巧,实际上可以实现吗?还是我想打风车?


通过以下解决方案,我可以实现自己想要的功能,但确实感觉像是一种骇人听闻的方式,而不是我希望在我的代码库中提供的东西。

- (nullable id<UserPaymentCard>)validCardForLocationWithId:(ObjectId)locationId {
    id<LocationsReader> locationsReader = [self locationsReader];

    __block LocationStatus *status = nil;
    __block BOOL flag = NO;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [locationsReader fetchLocationProviderStatusFor:locationId completion:^(LocationStatus * _Nonnull locationStatus) {
            status = locationStatus;
            flag = YES;
        } failure:nil];
    });

    while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) && !flag){};

    return [self.paymentCards firstCardForStatus:status];
}
Run Code Online (Sandbox Code Playgroud)

Dam*_*zot 1

我想fetchLocationProviderStatusFor:completion:failure:在主队列中调用这些回调。这就是为什么你会陷入僵局。不可能。我们还不能进行时间​​旅行。