Reference:
App Architecture
添加网络的挑战
为程序添加网络支持时,会面临一些额外的挑战,这不是某个架构所特有的问题,也和本节中对于网络层如何架构的讨论无关,但是对于一款需要从网络中获取数据的APP,或多或少都需要清楚对于这些问题的思考:
- 额外的失败来源:任何从网络获取数据的尝试,都可能由于一系列的理由以失败而告终。我们必须考虑如何优雅地处理这些错误,而且经常还要为展示这些错误创建额外的UI。
- 获取最新数据副本:持续从网络监听数据要比观察本地数据困难得多,这往往导致我们需要周期性地手动获取数据。
- 多端间的数据冲突:网络引入了多端更新同一个数据的可能性,这可能导致潜在的冲突。网络上的数据可能会有独立于app的更改、引用的资源可能会在不通知客户端的情况下直接失效、两个客户端有可能更新了同样的对象。
对于两个客户端更新了同样的对象,这必须让服务器从两者间选择出哪一个应该胜出,并且告诉每一个客户端冲突的解决方案,可以参考iCloud关于解决文档冲突的方式和相关思考。
添加网络层的方式
为APP添加网络层有两种常见的方式:
- Controller层持有网络:将model层移除,并让controller来处理网络请求。数据直接从网络获取,从网络获得的数据不会被持久化,而是由controller负责将它们以处理view state相同的方式缓存在内存中。这种方式非常的简单直接,主要问题在于不同的controller之间进行数据共享变得非常麻烦。
- Model层持有网络:保留model层,并在model的下方加入了一个网络层。model负责触发和管理网络请求,并按照需要,用请求的结果来更新model,model的变更依然通过观察者模式传递给controller。在这种方式中,封装的网络服务可以提供接口直接由model层调用,也可以观察model的变更然后进行数据同步的网络活动,后者model层和网络层之间的耦合更低;因为保留了model层,利于不同controller间数据共享的同时,也可以很方便的做离线缓存。
Controller层持有网络
1.获取初始数据
controller发起网络请求,并且在数据返回时对view进行配置,controller只维护前一次请求所获取的数据的内存缓存。因为网络获取数据是一种延时操作,所以需要添加数据获取过程处于不同的状态、已经状态变更的额外逻辑。
2.更改数据
数据的更改现在也是一个通过网络执行的异步任务,view action传递到controller中,controller发起数据变更的网络请求,并且在数据返回时更新view。
3.思考&讨论
Controller层持有网络将大量的新的职责放到了controller中,包括发起网络请求,处理结果,以及处理网络失败等,这可以通过将这些代码封装为网络服务来减少controller中的代码。不过在这种方式还存在其他弊端:controller负责进行网络请求并持有数据,实际上数据的逻辑已经等同于view state,如果app中没有其他部分依赖这些数据,这种方式也可以良好工作,但如果数据需要在不同controller中进行使用,缺少model层让数据共享变得更加麻烦,而且即使当前不需要共享,也需要考虑到未来可能会有变更,所以从一开始就选择对未来友好的方式可能会更加明智。
Model层持有网络
1.加载初始数据
创建model对象,调用model的数据加载方法,在model的方法中,去触发相应的网络请求,根据请求的结果,model更新自己,而controller则观察model的变更并更新相应的view即可。
2.更改数据
controller与model进行交互,就好像model只是本地数据一样,网络则发生在model层的背后。但对于model如何触发网络请求,则有两种不同的可选方式:
- model直接发起网络请求:在model数据变更的相应接口中,直接发起网络请求,同步数据的变更。
- 网络服务观察model的变更:封装的网络服务观察model,model在数据变更时触发某种通知,网络服务在接收到信号时,再发起相应的网络请求。
第二种方式让model层和网络层进一步的解耦,同时因为封装了相应的网络服务,可以使用一个更改队列来对这一类网络请求做统一管理,并对待处理更改队列进行持久化,这样即使APP离线时(断网、退出、崩溃)本地更改也不会丢失。
3.讨论&思考
model持有网络为代码增加了一些复杂度,但也具有更多的能力:保留了model,让controller之间的数据共享更加方便,同时也很容易做数据的离线缓存;通过添加网络服务部件来管理数据同步的网络请求,可以在APP中立即更新数据,而不用等服务器的响应,但同时也需要增加额外的代码,来追踪未提交的变更,并对变更提交时可能发生的冲突进行处理。Model层持有网络是对APP未来变更和扩展更加友好的方式,是更加推荐的网络层架构模式。