2008-12-16 94 views
26

我正在设计应用程序的阶段,该应用程序将使用REST Web服务,并且在使用异步与同步与线程之间存在困难。这是场景。iPhone应用程序中的异步与同步与线程

假设您有三种深入的选择,每种都有自己的基于REST的资源。我可以用同步请求延迟加载每个请求,但这会阻止用户界面,并阻止用户在检索数据时碰到后退导航按钮。这种情况几乎适用于,除了,当你的应用程序需要登录屏幕。由于这个原因,我看不出有任何理由使用同步HTTP请求。唯一有意义的是让工作线程发出同步请求,并在请求完成时通知主线程。这将阻止该块。接下来的问题就是在代码中标记代码,看看哪些代码有更多开销,线程同步请求或异步请求。

异步请求的问题是您需要设置智能通知或委托系统,因为您可以在任何给定时间对多个资源发生多个请求。他们的另一个问题是如果我有一个类,比如说一个处理所有数据的单例,我不能在getter方法中使用异步请求。这意味着下面的不会去:

- (NSArray *)users { 
    if(users == nil) 
     users = do_async_request // NO GOOD 

    return users; 
} 

,而以下几点:

- (NSArray *)users { 
    if(users == nil) 
     users == do_sync_request // OK. 

    return users; 
} 

您也可以享有优先权。我的意思是优先考虑的是,如果您查看iPhone上的Apple的Mail应用程序,您会注意到他们首先会删除整个POP/IMAP树,然后再次请求检索邮件的前两行(缺省值)。

我想我的问题给你的专家是这样的。何时使用异步,同步,线程 - 以及何时在线程中使用异步/同步?当异步请求完成时,您已经设置了什么样的委派系统来知道该怎么做?您是否优先处理异步请求?

对于这个太常见的问题,有一个解决方案的色域。破解一些东西很简单。问题是,我不想破解,我想要一些简单易维护的东西。

回答

7

我不认为有一个“正确的”答案。看起来你明白所涉及的妥协,你只需要围绕这些做出设计。

一些额外的随机点:有时您的应用程序会强制使用特定的方法。例如,许多便利(即同步)方法将不允许认证。对我而言,这意味着我做出了决定。

对于Yummy我结束了而不是使用线程。我使我所有的网络调用都是异步的,并使用默认的XML解析器(使用回调函数)。由于它全部由事件驱动,每个单元都很小,因此GUI可以很流畅,而且不会增加线程的复杂性。

我使用状态机来找出为什么我得到一个特定的响应,以及一个队列,以便我只需要在任何给定时间“在飞行中”进行单个操作。对大多数请求都有明确的顺序,所以我不需要优先系统。

网络代码是我的应用程序中最复杂的,并且花费很长时间才能使工作强度大大降低!

+0

斯蒂芬,我认为一个状态机和队列将帮助我吨。我假设你在任何地方都没有例子? – Coocoo4Cocoa 2008-12-16 16:18:29

+0

“状态机”是对它进行表述的一种相当宏伟的方式......它是一些布尔和一些switch语句。没有什么非常聪明的,但我发现预先绘制在一张纸上是有用的。队列只是一个NSMutableArray。 – 2008-12-16 22:46:14

1

我个人看看正在做什么,我会通常使用asyc请求来确保UI不会阻止,但是,我可能会在请求过程中禁用我的应用程序的UI。

一个最好的例子就是我用“搜索”按钮构建的应用程序。一旦搜索被触发为异步请求,我会禁用按钮,直到响应回来,有效地限制用户产生第二个asyc请求的能力。

这样做,至少我可以防止对优先事项的需求,只有在您可以以简单的方式进行操作时才允许这样做,并且一次只限制一个操作。

1

我会建议异步的方式,没问题。然后,只在需要时加载信息,并使用委托系统将该信息提供给正确的对象。

您不想阻止用户界面。永远。并且异步加载信息允许您更好地控制发生的事情,以便在需要时可以发出错误消息。

-1

为什么你不能使用异步请求,就像这样:

- (NSArray *)users { 
    if(users == nil && !didLaunchRequestAlready) 
     users = do_async_request // Looks good to me 
    return users; 
} 

异步绝对是唯一的选择 - 唯一真正的问题是,如果你想开始使用单独的线程,或者如果你想只使用异步呼叫。从那里开始,如果你真的需要管理线程。

+0

你的return语句会在异步请求完成之前执行,所以你不会得到结果,只是nil。 – 2009-08-15 14:41:19

+0

@Danny:你可能想要设置一个委托方法/通知,它会表示请求已完成,并填充UITableView或其他内容。 – sebnow 2010-08-15 09:31:00

8

我不打折异步委托调用,但我通常最终使用同步请求的线程工人类。从长远来看,我发现拥有一个定义良好的线程化API更容易,而不是用管理异步方法之间状态的代码填充控制器。你甚至可以在你的工作线程中进行异步操作,尽管通常使用同步方法比较容易,除非它们不支持你需要使用的功能。当然,所有这些都取决于具体情况,我可以想到很多情况下,简单地使用异步方法将是最佳路线。

绝对考虑NSOperationQueue,如果你走这条路线;它大大简化了创建多个工作线程,并且还支持操作之间的优先级和依赖关系。现在在10.5上有一些问题,但我没有听说iPhone上有任何问题。

1

只是想:如果你想使用iPhone的单元测试框架,你可能想要有同步功能,因为这可能会使测试更容易编写。

但是,您的某些API可能无法同步工作,因此您需要将它们转换为同步任务。如果执行单元测试的代码在其自己的线程中运行,那么可以编写一个包装,等待异步任务完成。

要做到这一点,您需要使用信号量:您的包装函数启动异步操作,然后使用信号量来阻止自己(即将自己置于睡眠状态)。指示异步事件结束的回调释放信号量,以便睡眠包装线程可以继续并返回。

0

我会同步使用dispatch_async。这样,你有没有代表/ NSNotifications的优势,它是非阻塞

- (NSArray *)users { 
    if(users == nil) { 
     users = do_sync_request(); 
    } 

    return users; 
} 

// now when calling the users method, do this 

- (NSArray *)getUsers { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      NSArray *users = [self users]; 
      dispatch_sync(dispatch_get_main_queue(), ^{ 
       return users; 
      } 
    } 
}