非常简单的用例:假设iOS应用显示MovieListController
视图(在UINavigationController
内),其中包含电影列表。当用户触摸其中一个时,该应用会将MovieDetailController
推送到导航堆栈(即[[MovieDetailController alloc] initWithMovieId:(NSString *)
。在MovieDetailController
的{{1}}方法中,它会生成HTTP调用以根据传入其中的电影ID检索详细信息。
挑战在于viewDidAppear:
被立即推到导航堆栈上,并且在未检索到细节的情况下持续一两秒,视图显示了一堆空白字段,这是不希望的。
为了解决这个问题,我想到MovieDetailController
没有立即将MovieListController
推到堆栈上。相反,它会建立一个进度指示器(我使用SVProgressHUD),然后调用MovieDetailController
MovieDetailController
方法启动HTTP调用。然后,当收到数据时,initWithMovieId:
会回调MovieDetailController
以删除进度指示器,然后将MovieListController
推送到导航堆栈。
这种情况有更好的模式吗?我应该考虑将MovieDetailController
推送到导航堆栈上吗?
注意:我已考虑加载详细信息视图并设置活动指示符,但您仍然可以看到“空白视图”'它背后看起来有点奇怪。我还考虑让MovieDetailController
检索详细信息,但这似乎打破了封装模型 - MovieListController
应该关注列出电影,而不是关于它们的细节。
有什么想法?这部电影只是一个例子 - 在这里寻找一般模式。
答案 0 :(得分:5)
我个人会采取以下方法。
我之所以选择此路线而不是在推动视图控制器之前显示HUD,是因为您可以让用户取消他们的选择。我不熟悉SVProgressHUD
但希望在显示HUD时你可以启用触摸,特别是用户触摸你UINavigationController
时他们意外选择了电影,或者请求的时间比他们愿意等待。
它还将列表视图中的逻辑分开,您的详细信息视图是独立的,可以在应用程序的任何位置进行初始化(可能您希望在电影详细信息视图中交叉链接类似的电影)并且您不需要重写逻辑等待结果回来的呈现视图。
答案 1 :(得分:2)
在这种情况下,我个人会回到模型 - 视图 - 控制器模式。
有几个系统应用程序显示对象列表中的详细信息视图,例如日历,联系人等可能与其各自应用程序中的EKEvent
和ABPerson
一样,主视图控制器维护模型对象的列表。当用户选择其中一个项目时,主视图控制器将所选模型对象传递给详细视图控制器。详细视图控制器本身不必进行任何数据加载。因此,就像@ChrisWagner所说,我们希望将逻辑与视图控制器分开。
同样,您可能希望使用存储MovieList
个对象数组的Movie
类。每个Movie
都存储详细视图控制器中所有字段的值 - 实质上是应用程序所需的有关电影的所有信息。例如,您可能拥有属性NSString *movieTitle
或NSDate *premiereDate
。 movieTitle
将在初始化时由MovieList
设置,因为它只是元数据;另一方面,如果数据未加载,则premiereDate
可能为nil
,因此您将拥有一个属性BOOL isLoaded
来检查此情况。
然后您可以采用以下两种方式之一:
1)假设主视图控制器想要推送电影的详细视图控制器。然后主视图控制器将从Movie
中挖出适当的MovieList
并检查它是否已加载。如果没有,它将在-(void)loadContents
上调用类似Movie.
的内容。当模型对象完成加载时,它将发布一个通知,表示已完成加载。此时,主视图控制器将关闭其进度视图并推送详细视图。如果使用(1),使用MovieList
协调员并不重要。
2)如果您想更加积极地加载电影信息,可以在MovieList
上实施一种方法,在后台loadContents
上调用Movie
。然后,当用户选择电影时,电影已经被加载的可能性更大。
编辑:请注意,如果您决定使用MovieList
类型对象,则只允许主视图控制器访问此列表。在某种程度上,我所描述的模型结构与视图控制器结构平行。详细视图控制器不知道列表视图控制器,因此它也不应该知道MovieList
。
使用此Movie
和MovieList
结构的好处是数据模型与视图控制器完全分离。这样,用户可以在加载数据时自由取消,选择,显示和关闭视图控制器。 (想象一下,如果用户按下Back以关闭进度HUD,则取消它将收集的任何HTTP数据。然后,如果他决定回到同一部电影,则新的详细视图控制器必须重新开始加载。 / em>)另外,如果您决定在开发过程中替换视图控制器类,则不必复制和粘贴一堆数据处理代码。
我认为您会发现以这种方式构建您的应用不仅可以为您和用户提供更多自由,还可以使您的应用高效并且可以在以后的扩展中使用。 (抱歉发布这么晚了,但我想在这个与模式相关的讨论中加入MVC!)
答案 2 :(得分:1)
我认为更高级的路线是在tableview / collection视图中显示单元格时启动详细请求。然后当单元格移出屏幕时,取消请求。你可能会不必要地加载电影细节,但我认为这不是什么大问题,因为你只会用你可能不需要的电影细节填充你的数据库,而coredata可以处理它。这假设您的api请求发生在bg线程上,并且它们不会影响主(UI)线程。