等待主线程,直到异步过程完成?

时间:2010-12-16 06:12:37

标签: iphone objective-c

我正在使用正在进行异步网络调用的代理。响应将被处理并作为参数传递给下一行中的方法。代码说明如下:

- (MyClass *) performOperations{
  ...
  ...
  [self callProxyMethodsTarget:self action:@selector(receivedValue:) withObject:anObject]; //making an asynchronous call here
  return response;
}

- (void) receivedValue:(id)response{     ///need this return value from network call to return from performOperartions
  ...
  ...
}

我的问题是,由于代理方法正在进行异步网络调用,我无法及时获得响应以返回它。

我想过很多事情,比如:

  • 使网络调用同步,但这需要大量的返工,并可能引入无法预料的问题
  • 更改返回类型并从receivedValue传递响应,但不能这样做,因为我的客户端已经定义了这些方法名称和返回类型,而在其他平台上,团队正在使用同步调用

我想到了一个像以下的解决方案:

 - (MyClass *) performOperations{
      ...
      ...
      [self callProxyMethodsTarget:self action:@selector(receivedValue:) withObject:anObject]; //making an asynchronous call here

      ///write a code here to wait until response is received
      return response;
    }

    - (void) receivedValue:(id)response{     ///need this return value from network call to return from performOperartions
      ...
      ...
    }

但未能这样做。

3 个答案:

答案 0 :(得分:2)

我假设没有从主线程调用performOperations,因为如果是,那么你就麻烦了。否则,您可以像这样使用当前的运行循环:

- (MyClass *) performOperations{
  _isValueReceived = NO;
  ...
  ...
  [self callProxyMethodsTarget:self action:@selector(receivedValue:) withObject:anObject]; //making an asynchronous call here

  // Start with 10ms time boxes
  NSTimeInterval ti = 0.01;
  // Wait until delegate did callback
  while (!_isValueReceived) {
    NSDate* date = [NSDate dateWithTimeIntervalSinceNow:ti];
    // Let the current run-loop do it's magif for one time-box.
    [[NSRunLoop currentRunLoop] runMode:NSRunLoopCommonModes
                             beforeDate:date];
    // Double the time box, for next try, max out at 1000ms.
    ti = MIN(1.0, ti * 2);      
  }

  return response;
}

- (void) receivedValue:(id)response {
  ...
  ...
  _isValueReceived = YES;
}

这就像你的后台线程的魅力一样,而且正是GNUStep如何使用异步I / O实现分布式对象的同步方法调度,所以应该非常接近Cocoa在内部的方式。

然而,在主线程上执行安全,因为UIKit在默认模式下重新进入运行循环是不安全的。

答案 1 :(得分:1)

您需要稍微重构一下您的应用程序。您不能等到结果到达的位置,因为这将阻止主线程,这意味着运行循环上的事件将不会被服务。这有两个原因

  1. 用户将遇到锁定的应用程序
  2. 异步回复很可能作为事件发布到运行循环中。这意味着你永远不会看到它,你将永远被阻止。
  3. 您需要为应用程序创建一些状态,例如标记proxyRequestMade并在您发出请求时设置它。然后该方法将返回到运行循环而不返回值。

    然后,当您收到响应时,您需要处理它并重置标志。您拥有该标志的原因是它可能会改变您处理其他UI事件的方式,例如您可以在发出请求时禁用某些按钮。

答案 2 :(得分:0)

代理方法是否具有表明其操作已完成的委托协议?

如果是这样 - 我不知道你的情况,但如果你控制了代码,那么你可以添加它们 - 然后你可以将调用对象设置为代理方法的委托,调用代理调用方法结束时的方法,并在调用委托方法时恢复。

编辑示例代码

您的方法无法像现在这样工作,因为第一个方法 - 调用代理方法的方法 - 无法返回值。它可能需要有一个委托协议,无论是什么调用它。

- (void) performOperations {
  ...
  if (proxyMethod == nil) {
      ProxyMethod *proxyMethod = [[ProxyMethod alloc] init];
  }
  [proxyMethod callProxyMethodsTarget:self action:@selector(receivedValue:) withObject:anObject]; //making an asynchronous call here
}

//Assuming this the the delegate method from the proxy object
- (void) receivedValue:(id)response {   
    // Continue with calling thread here
    // Return information to whatever called performOperations via
    //    a delegate method or a notification
}