让我们看一个典型的 RESTful iOS 应用程序,假设是一个联系人应用程序,主屏幕是联系人列表,当点击联系人时,您会进入联系人详细信息屏幕。
联系人列表是通过 REST API 获取的,联系人详细信息是通过另一个 API 获取的。
您将使用哪个事件来触发对这些 API 的调用:
viewDidAppear
在两个视图控制器上viewWillAppear
在两个视图控制器上pushViewController:detailViewController
目前我主要在这种情况下使用
viewWillAppear
,或者在某些特定情况下使用viewDidAppear
,但为了标准化我的编码实践,我想明确确定这些不同方法的优缺点。
这在一定程度上是一个偏好问题。由于 API 调用将产生未知的延迟,因此应用程序应显示 UI 来指示其正忙。我的偏好是让 UI 在请求之前执行尽可能多的操作。 (我天真的认知模型是,在获取数据时查看新 VC 的 UI 会瞬间占据用户的注意力,使滞后看起来更短)。
因此,我更喜欢描述请求的 VC 的参数 - 比如要在详细 VC 上获取的联系人 id,并在 viewDidAppear 上执行请求(如果数据尚未缓存或需要刷新)。在该方法中,放置一些 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 中预取尽可能多的数据。这就是像
AFIncrementalStore
这样将 API 映射到 Core Data 的库尝试做的事情。但是,如果您有数千个联系人,速率受到严格限制,或者带宽受到限制,这将是一个问题。
绝对可以肯定的是,您希望尽快调用您的网络 API,以便用户体验到最小的延迟。您可能会发现在这种情况下使用 viewDidLoad
而不是
viewWillAppear
或
viewDidAppear
可能效果更好:您可以使用加载/保持图形或动画设置视图,触发异步网络调用,然后完成后显示所需信息。
在 viewWillAppear 上加载联系人,如果您有下拉刷新,则何时发生。
当用户点击单元格时,在处理该事件的方法中,加载事件详细信息,并将该对象传递给联系人详细信息控制器的构造函数,然后推送它。