美文网首页iOS Developer程序员
给你的地图模块动手术

给你的地图模块动手术

作者: ccSundayChina | 来源:发表于2017-05-22 22:00 被阅读606次

背景:地图对于很多应用来说已经不是一个稀罕的东西了,很多软件里都有这个功能,特别是那些房产类、外卖类的应用,地图可以算是其中一个很重要的模块。通常情况下,地图是在这些应用的早期开发的,赶着时间开发,因此难免会存在设计粗糙、耦合严重的情况。随着产品线的不断发展,地图模块也变得越来越臃肿,来一个功能就往里面扔,久而久之,哪怕只是对它做一点小的改动,都会比较费劲。这也是为什么很多开发者不愿意产品老是调整地图的原因,因为实在是改不动了。

然而逃避终究不是解决问题的办法,放着不管,只会越来越严重,有病还是要趁早治。

今天我们就来看一下,怎么给一个臃肿的、已经病入膏肓的地图模块做手术。

医生看病时要先了解病人的情况,然后对症下药,那些胡乱开药的医生一定都不是好厨子。因此首先应该花点时间好好的了解这个“病人”的情况。在看了一天的自家项目中地图模块的“病”后,我总结了一下我们项目中地图模块的问题,这个问题,应该也是大部分地图模块的问题,在每一个问题的后面给开出对应的“药方”:

  • 声明了大量的用来记录搜索条件的全局变量。在地图中通常会有搜索的功能,需要记录用户的各种搜索条件,像我们这种房产类的软件,查询条件要有十五六个,然后就很黄很暴力的声明了十五六个全局变量来进行记录,再加上存放查询结果的数组、字典和其他的中间变量,那简直叫一个酸爽啊。其实我们完全可以声明一个模型来管理这些搜索条件、存储搜索结果以及其他的中间变量,这样做的好处很多,不仅可以很方便的设置默认值。并且在其他类中要使用数据的话,只需要耦合一个模型就好了,方便管理,另外还可以通过优秀的框架(自行百度)将模型直接转换为对应的字典,传给服务器,你只需要过滤掉那些不该上传到服务器的字段就可以了。

  • 网络层没有分离出来,很多人纠结于网络层属于MVC中的哪一层,因为貌似那里面没有考虑到它们的位置,因此就将大量的网络请求写到了视图控制器里,然而先不论MVC中对网络层的定位如何,网络层负责的功能就是根据请求参数获取数据,然后对数据做跟业务强相关的转换与处理,除此之外貌似也没有别的了,它的职能是明确的、单一的,也是固定的,完全可以声明一个专门处理该业务相关的网络请求的对象,传给它请求参数,它处理后返回给你想要的结果,就这么简单。视图控制器不需要去关心它里面怎么对数据进行处理与转换。

  • 视图控制器直接操作mapView,在VC中直接操作mapView貌似是一件很正常的事情,然而仔细去看的话,会发现我们对mapView的很多操作是跟业务无关的操作,比如mapView的创建、定位到当前所在位置、设置地图层级等功能是跟业务没有什么关联的弱业务,而像添加标注Annotation模型,因为会涉及到添加自定义的Annotation的问题,这个是跟业务强相关的,变化的可能性是比较大的,如果要加一种新的标注类型,那么我们就要到视图控制器里,在上千行代码中找到这块功能进行修改,不便于模块测试,所以还是有必要声明一个mapViewmanager来管理这些事情,其中弱业务可以直接写在manager里,而那些跟业务强相关的(主要就是标注Annotation模型的创建与添加)可以写在manager的分类中处理。以后要加新的标注模型的话,直接到分类中进行修改就可以了。

  • mapView的代理没有从视图控制器中剥离出来mapView的代理方法有好多,如果将这些代理方法全都写到视图控制器中的话,那么势必会造成VC中的代码过多的情况,特别是根据Annotation返回对应的标注视图的代理方法,这个方法跟具体的业务强相关,如果你的地图中需要根据地图等级、用户身份等条件显示不同的标注视图,那么最好还是单独声明一个MapViewDelegate类来做这个事情吧,好处就是减轻了VC的压力,并且所有跟标注视图相关的逻辑处理都单独剥离出来,也方便你以后的维护。

再将代理从视图控制器中分离出来后,很自然的就会遇到一个问题,那就是标注View的点击事件谁来处理,换句话说就是它的target是谁。

如果没有剥离出MapViewDelegate,那么我们的做法通常是将视图控制器VC作为这些标注的target,所有的点击事件都是视图控制器进行处理,现在既然剥离了,总不能在MapViewDelegate中再去耦合具体的视图控制器吧,这样的话它的复用性就会降低,怎么解决这个问题呢?

声明MapViewTargetProtocol协议

在这里我们声明了一个协议来解决这个target问题,将所有标注View的点击方法都写在了这个协议里,并且这些方法是必须实现的方法。这样一来凡是遵循这个协议的对象都可以作为标注视图的target,这样MapViewDelegate中就不需要再耦合某个具体的target了,实现了一定程度的解耦,在使用中,由于我们的点击事件不多,所以我们让视图控制器遵守了这个协议,但是如果标注的点击事件过多,那么我们就可以专门声明一个类当做这个target,解放视图控制器。

以上就是针对地图模块的解耦方案,以下是上面提到的几个类:

  • MapSearchKeyModel,用来管理所有数据的模型,需要被下面的类耦合。
  • MapViewManager,用来管理mapView,并处理mapView的弱业务逻辑。
  • MapViewManager+Annotations,分类,专门用来处理annotations标注模型。标注模型的添加与移除都在这里进行。
  • MapNetWorkManager,负责网络请求,处理返回数据。
  • MapViewDelegate,专门用来实现mapView的具体代理方法,所有标注视图的处理都在这里。
  • MapViewTargetProtocol,用来解决标注视图Viewtarget问题。
  • MapViewController,视图控制器。

这样一来,我们的视图控制器中的代码就从天杀的1700行锐减到了350行,并且各模块的职责清晰,应该够它再活蹦乱跳一段时间了。
因为它不是很丑了。。。(哈哈,长得好看果然在哪里都有用)

此处应有demo

相关文章

网友评论

    本文标题:给你的地图模块动手术

    本文链接:https://www.haomeiwen.com/subject/ipeixxtx.html