“嵌套” iOS应用程序体系结构

在深入探讨之前,首先让我给您一些有关“嵌套”的信息。

无论团队位于单个组织内还是独立公司,Nested都是一个团队到团队的交流平台。 我不会向您解释嵌套的更多内容,因为它本身就是文章。

我大约在一年前加入团队,当时该项目处于Beta测试阶段,并且正在进行一些重组。 服务器正在从PHP迁移到GoLang,许多场景和模型将被完全更改和重构。

我以Nested作为一名Android开发人员开始工作,当时的android应用存在很多问题,尽管其中只有少数对用户可见且明智。 主要问题很简单,结构的设计根本没有灵活性。

我的祖先不是一些新手开发人员,但项目定义以及开发人员在一年中已经更改了两次。 但是最重​​要的是缺少文档。

我将该应用程序维护了一个月,但是由于新版本完全不同(甚至用户界面设计也被完全更改),所以我几乎从头开始开发该应用程序。

Nested存在一个大问题,这使其难以开发和维护:作为使用WebSocket与Server进行通信的实时应用程序。 因此,我要做的第一件事就是开发一个平台来像其他常见的HTTP库一样发送请求并获得其响应。

我选择Volley的原因仅仅是因为它一直是(现在仍然是)我最喜欢的用于通过HTTP与服务器通信的库,所以我为WebSocket开发了完全相同的平台。

但这仅仅是开始,发送请求和获得响应并不是Nested的大问题,但是应用程序应该在收到来自服务器的特定同步信号后进行自我更新。 就是在我向项目“ SyncManager”中添加新零件时。

2个月后,Android版本获得了稳定性,由于找不到可靠的iOS开发人员,我接受了自己开发iOS应用程序的挑战。

当然,我从文档开始。 用Java编写大约6年后,[我爱JAVA! [不要与我讨论!] Swift是一种安全的语言,很容易引起我的注意。

从Android迁移到iOS并不是一件容易的事,但是我决定忘记有关Android的所有知识,而像一个没有任何先入之见的全新平台一样面对iOS。

我开始研究设计模式和体系结构,并根据Nested的实时环境选择了经过细微改动的简单MVC,因为我们应该尽快开发它,三个月后,第一个生产版本已经发布。发布,现在是我保留的时间,可以在项目变得太大而无法更改之前考虑早日进行重组。

我当时在阅读有关VIPER的信息,但对我们来说这还不够方便,然后我设计了自己的产品。 下图是我们的架构概览:

现在让我们开始描述图中的每个实体:

视图控制器:

正如其本身所说,View Controller是一个简单的视图控制器,类似于iOS中的默认UIViewController,但具有更多的功能和参数。 我在项目中将其称为“ BaseViewController” ,几乎所有的视图控制器都扩展了该类。

我添加的一些参数如下:

  1. isVisible:布尔; 此变量实际上与“ viewWillAppear”和“ viewDidDisappear”这两个本地函数一起使用
  2. hasUpdate:布尔; 该变量指示控制器在不可见时是否接收到任何更新信号。
  3. subscriptiondSyncs:[Int]; 是控制器在“ SyncManager”中预订的同步类型的列表,例如: [SyncManager.POSTS_SYNC,SyncManager.COMMENTS_SYNC]
    (再次查看该图)
  4. missedUpdates:[String :(类型:Int,fieldId:String,数据:Any?)]; 这是一个字典,如果该控制器当前不可见,则该字典保存该类型的最后一个更新对象,例如,如果您收到了一个Post的两个更新,则只有包含最新数据的最后一个更新对象才会被保存。存储。

与该体系结构相关的额外功能是:

  1. syncData(type:Int,fieldId:String,data:Any?); 由于在解释了参数之后该函数的实现已经很清楚了,所以我只复制代码:
    func syncData(type:Int,fieldId:String,data:Any?){
    .. if!isVisible {
    .. .. hasUpdate = true
    .. .. missedUpdates [“ \(类型)_ \(fieldId)”] =(类型:类型,字段ID:字段ID,数据:数据)
    ..}其他{
    .. .. updateDataBySync(type:type,fieldId:fieldId,data:data)
    ..}
    } //(点只是为了更漂亮的外观)
    每当SyncManager收到控制器已预订的同步信号时,就会调用此函数。
  2. updateDataBySync(type:Int,fieldId:String,data:Any?); 是将在更高级别的类上实现的方法。
    每个控制器都可以根据其视图和定义的策略来决定如何处理接收到的数据,因此实现完全由您自己决定。

还需要清除一些要点; 订阅过程从“ viewWillAppear”回调开始,同样在收到内存不足警报后,视图控制器取消订阅自己并清除错过的更新列表。
每个控制器都从DataFactory接收有关“ viewDidLoad”的初始数据,此后,将通过“ viewDidAppear”内部的“ hasUpdate”检查数据的更改。

数据工厂

数据工厂是该体系结构最重要的部分之一,它处理数据,将其存储在数据库中并进行更新。
对于每种数据类型,Data Factory提供三种方法:

  1. getData(update:Bool)->可以吗? 调用此方法,如果数据库中存储了任何内容,Data Factory将返回所需的数据。
    如果update为true,DF将[通过RequestManager]向服务器发送请求以获取最新数据。
  2. updateDataFromServer(); 顾名思义,此函数将向服务器发送请求以获取最新数据。
  3. updateData(data:任何); 此方法使本地存储[/ Database]更新为最后接收到的一种类型的数据。

在Nested中,为了易于使用和理解,我为每个模型定义了这三个功能,例如:
– getPosts(forPlace id:String,sortByRecentActivity:Bool,update:Bool)-> [发布]
– updatePostsFromServer(forPlace id:字符串,sortByRecentActivity:Bool)
– updatePosts(forPlace id:字符串,帖子:[Post])

当Data Factory在调用“ updateDataFromServer”之后从服务器接收到一些新数据时,它将通知SyncManager接收到的数据及其类型,因此SyncManager可以将该类型的数据通知订阅的控制器。

要求管理员

请求管理器是类似于“ Volley”的平台的最高级别实体,用于发送请求并传递对请求的接收响应(与“ Broadcaster”一起)。

无需在这里解释其功能。 因此,只需考虑其在流程中的作用。

播音员

广播公司拥有决定从服务器接收的每个有效载荷的逻辑。

通常,在嵌套中,有两种有效负载,一种是与发送的请求相关的响应,另一种是同步信号。

通过第一种类型,Broadcaster首先指示响应是否为错误,然后在RequestManager中找到相关请求并调用其响应/错误回调函数。
第二,广播公司反序列化接收到的JSON,并在SyncManager中调用“ sync()”函数。

PS:您可能已经注意到我们的设计模式是 “ Singleton”, 并且每次我们谈论一个实体时,我们都在谈论它的实例。

同步管理器

用一个词来描述它,Sync Manager是一个路由器。
它为每种类型的操作保留订户,并在每次同步信号及其数据到达时通知他们。
此外,Sync Manager知道用户当前可以看到哪个控制器(在顶部),以便显示错误警报。

逻辑很简单,根据模型和从服务器接收的同步对象,每个项目中的逻辑都可能不同。 因此,在实施它时只需考虑其角色:它将成为路由器。

_____________
现在我们已经完成了细节。 本文的目的首先是,如果您在项目中遇到类似的挑战和问题,这将是对您的启发。
但是,我真的很想知道您的反馈或优化提示,所以请不要犹豫在上面给我留言。