Iphone RESTful iOS应用程序-何时更新模型-最佳实践
让我们来看一个典型的RESTful iOS应用程序,比如说联系人应用程序,主屏幕是联系人列表,当点击联系人时,您会进入联系人详细信息屏幕 联系人列表通过RESTAPI获得,联系人详细信息通过另一个API获得 您将使用哪个事件触发对这些API的调用:Iphone RESTful iOS应用程序-何时更新模型-最佳实践,iphone,ios,api,model-view-controller,rest,Iphone,Ios,Api,Model View Controller,Rest,让我们来看一个典型的RESTful iOS应用程序,比如说联系人应用程序,主屏幕是联系人列表,当点击联系人时,您会进入联系人详细信息屏幕 联系人列表通过RESTAPI获得,联系人详细信息通过另一个API获得 您将使用哪个事件触发对这些API的调用: 视图显示在两个视图控制器上 视图将显示在两个视图控制器上 在调用pushViewController:detailViewController之前,从主视图控制器调用contact detail API 还有其他活动吗 目前,我使用的ViewWi
- 视图显示在两个视图控制器上
- 视图将显示在两个视图控制器上
- 在调用pushViewController:detailViewController之前,从主视图控制器调用contact detail API
- 还有其他活动吗
当用户点击单元格时,在处理该事件的方法中,加载事件详细信息,并将该对象传递给contact details控制器的构造函数,然后推送它 这部分是偏好的问题。由于API调用将产生未知延迟,应用程序应显示指示其繁忙的UI。我的首选是让UI在请求之前尽可能多地执行操作。(我天真的认知模型是,在新VC获取数据时看着它的UI会占用用户的一瞬间,使滞后时间看起来更短) 因此,我倾向于使用VCs的参数来描述请求——比如在细节VC上获取联系人的id,并在ViewDidDisplay上执行请求(如果数据尚未缓存或需要刷新)。在该方法中,设置一些UI来指示正在进行提取,因此其形式如下:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (/* i don't have my model or it's out of date */) {
// put up 'i am busy' UI
MyRequestClass *request = // form a request that fetches my model
[request runWithBlock:^(id result, NSError *error) {
// i build my request classes to run with blocks simplifying the caller side
// if it's a json request, then pass a parsed result back to this block
// remove 'i am busy' UI
if (!error) {
// init my model from result
// other parts of this class observe that the model changes and updates the UI
} else {
// present error UI
}
}];
}
}
首先,最好确保API接口和数据访问在单独的数据访问类(或数据控制器-如果您已经这样做了,那么道歉,忽略这一段)中的视图控制器之外进行。您希望避免将网络代码直接放入视图控制器中,因为如果您想创建特定于iPad的视图,或者以后需要以某种方式修改UI,这将使您的生活变得非常困难) 有了这些,你有几个选择。从用户的角度来看,从RESTful API预取尽可能多的数据是最好的。这就是将API映射到核心数据的库(如
AFIncrementalStore
)试图做的事情。但是,如果您有数千个联系人,并且这些联系人的速率受到严重限制,或者带宽受到限制,那么这将是一个问题
可以肯定的是,您希望尽快调用您的网络API,以便用户体验到最小的延迟。您可能会发现,在这种情况下,使用
viewDidLoad
而不是viewwillbeen
或viewdidbeen
可能会更好:您可以使用加载/保持图形或动画设置视图,触发异步网络调用,然后在完成后显示所需信息。正确,我们同意所有API接口和网络代码都在视图控制器之外处理。我喜欢使用“模型控制器”类来处理所有这些,每当数据更新完成时,就会向视图控制器发送通知。我还在一些项目中使用AFIncrementalStore进行预取,在其他一些项目中使用RESTkit核心数据集成。尽管如此,我从未在viewDidLoad中进行任何此类调用,因为在大多数情况下,它只被调用一次,即使视图控制器通过导航被重用。啊,对不起,我正在考虑您的非常具体的示例(在UITableView
中的详细信息视图,在该视图中,您将为请求的每个联系人创建一个新的联系人。如果您使用的是VCs,那么您最好将其放在视图中,该视图将显示
,除非您想特别了解它,并根据用户在表中的位置等开始预取。这可能是过早的不过,e优化。你在这里提出了一些有趣的观点。我同意预取有时可能是个好主意,但如果某些东西没有预取,我想我对“尽快”的看法正好相反。我的观点(基于我刚刚在头脑中做的大量研究)建立下一个用户界面几乎不需要时间,用户吸收新用户界面的时间会从她对服务器请求延迟的感知中扣除。如果我是对的,那么这就支持“尽可能晚,在用户界面几乎每一次即时更改完成后”。但是,这可能只是我自己的pop cog scidanh,我不确定我是否能接受你的评论。如果请求是异步发送的,那么启动它几乎不需要时间,那么在视图中启动它会更好吗?这样在演示动画进行时,一些请求会被处理?@danh我理解你的意思。但是如果您使用核心数据进行缓存,那么实际上会看到ViewWillDisplay(这将立即很好地显示缓存的数据)之间的差异而ViewDidDisplay将在屏幕显示的最后显示缓存的数据,这会导致一点闪烁效果。因此我宁愿使用ViewWillDisplay。由于请求是异步的,我会在执行任何UI之前发送它。然后设置并显示带有某种“获取数据…”的UI占位符,然后在数据到达时填写字段。