iOS项目的基本架构<一>

      每个iOS开发者在做过一些项目之后,都会有自己的一些总结和积累,都会封装一些自己用得顺手的控件,俗称造车的轮子,关于UI层面的,我是建议少用甚至不用第三方的,虽然有些第三方的UI控件确实功能很强大,也很全面,但是,自己项目中用到的功能却往往只有其中的一两点,而且改动的时候需要通读别人的代码,费时,也显得不灵活。UI的东西都是高度定制化的,所以还是自己封装比较好,而且自己封装的东西印象深刻,思路和知识点都是自己的,改动起来容易。有点扯远了,今天要说的,并不是这些小控件,而是要探讨一下承载这些轮子的整个车子。就像建房子一样,只有整体的框架设计得合理了,整个房子才会牢固,那些砌砖加瓦的就会显得很容易,日后要替换这些砖瓦也轻松。当然,我写这篇文章,不仅仅是探讨技术问题,如果仅仅是探讨技术问题,那么我直接把demo丢到github上就可以了,而是记录一下整个的思路与思考的过程,希望能给到尚未走过来的小白们一些启发,我就觉得是一件幸事了。

      废话有点说多了,言归正传,转入正题吧。一个合理的商业级app的基本架构是怎样的?也许对一个新手来说,会觉得很模糊,新手拿到项目,拿到需求的时候,往往都是按着界面的需求来直接实现,往往是看到什么就先写什么,而不会从整体着眼去设计整个架构,更别说是设计出一个以后方便改动,通用性强的架构了。比如说,新手一打开app,看到的是,如果已经注册了,那就直接进入主界面,如果没有注册就先跳转到注册界面,那么,他可能会在AppDelegate的didFinishLaunch:方法中这样写:


咋一看,这样写在逻辑上没什么问题呀,合情合理的。确实,在逻辑和通功上,这样写,是可以实现的。但是,你的主管要是看到你这样的代码,就呵呵了!这样写有啥不好,我就不过多解释了,继续往下看你就会慢慢明白。

      那么问题来了,这样写不行,那怎样写才行,才比较好呢?我不会呀?对,当你还没有足够的经验和知识积累的时候,你对整体的架构是比较模糊的,因为当你连砌砖加瓦都还不熟练的时候,是不可能会整体去思考一个项目的架构的,当你经验不够的时候,很多问题你也是思考不清楚的,因为你没有踩过足够多的坑,你没有走过足够多的弯路,你是很难辨别出哪条是康庄大道的。但是,人人都是从小白过来的,我该怎么办呢?通常,解决这样问题比较好的方法有两种,第一,就是请教你的主管或者有经验的前辈,他们的一言真是胜读十年书的。如果你没有那么幸运,身边没有这样一个主管或者那么有经验的人,别灰心,还有第二种方法,那就是模仿,中国是世界第一模仿强国,你可要充分发扬中国人的特长呀,我这里说的模仿可不是贬义词哦。那怎样模仿呢?你可以打开QQ微信淘宝这些超级app,去看一下他们是怎么做的,你模仿人家的,就可以了,毕竟这些app都是经受过市场考验的,都是大神们写的。打开QQ的时候你就会发现,如果你已经登录了,就会跳到主界面,主界面是一个tabBarController,如果你没有登录,就会跳转到登录界面,但是,我没看出来什么呀?这不就是我上面说的那个逻辑吗?对,这么看确实是这样的,那么,你再打开淘宝看看,无论你有没有登录,一打开app,都会跳到主界面,主界面也是一个tabBarController,那么,就很清楚了,无论有没有登录,app的rootViewController都是主界面,如果你没有登录,而且你的app是要求登录过以后才能使用的,那么就在主界面上present出登录界面。这样子,整体架构就是,无论你有没有登录,app加载完都先进入主界面,如果要求登录,那就在主界面present出来登录界面,这样子app的rootViewController就永远是MainViewController,就像一棵树一样,无论怎样修整,我的根和主干只有一个,其他功能就是各个开枝,登录功能也是其中一个开枝,这样无论你添加多少功能都是在主干上添加,而主干是永远只有一个,回到主干的时候就永远是回到MainViewController,这样子,app的整个架构是不是就强壮了很多?紧密了很多?没那么散乱的感觉了。

      主干是MainViewController,这个确定了,那么主干是一个怎样的界面呢?你又可以打开别人的app看看,比如QQ微信这种社交类的,或者淘宝京东这些商城类的,或者是UC浏览器这些Web类,主界面基本都清一色是使用tabBarController,是的,没错,现在市面上95%以上的app主界面都是一个tabBarController,说明这无论是从开发者的角度还是用户的层面,都是被认可的。以tabBarController为主干,每个tabBarItem切入各自的分支,就构成了项目的整体架构。当然,要推出界面,就要嵌套一个UINavigationController,那么问题来了,是在NavigationController上嵌套一个tabBarController呢还是在tabBarController的各个分支上分别嵌套一个navigationController呢?苹果官方文档的建议是在tabBarController上嵌套navigationController,本人也觉得这样的做法比较灵活。那整体的架构就是这样了:


因为tabBarController最多只支持同时放5个tabBarItem,超过5个的时候最后一个就自动变成more,点击more的时候就会弹出一个列表,但是,通常别人都不太喜欢原生的这样方式,而是在左边弹出一个sideMenu,就像QQ那样的


就这样一个类似QQ的主题框架就成型了。

      接下来就是完善一些细节部分了。

      首先,我们不应该直接把tabBarController作为app的rootViewController,tabBarController有属于它自己的功能,只负责切换它自己本身的子控制器就行了,我们应该再new一个RootViewController作为app的rootViewController,用来完成一些app层级的操作。那么整个app框架就变成了这样


然后下面我们就来完善一下这个RootViewController,RootViewController的大致结构我是做成这样的


最下面放的是一个ScrollView,这个ScrollView的作用主要是用来适配键盘的弹出和收起的,这样就不用在每个会被键盘遮盖的界面都放一个ScrollView,只需要通过响应链来操作这个ScrollView就可以了,然后ScrollView上面放一个Container,Container Embed的是tabBarController。在app启动的时候通过这样的方法可以拿到tabBarController。在RootViewController上:


RootViewController可以通过这样的方式拿到:


到此,整体的框架就基本搭完了。

      接下来,我们还是继续完善细节部分,因为很多app都不喜欢原生的UITabBar,所以,我们也自定义一个UITabBar替换掉原生的。大概的效果是像下面这样的(样式不重要,只要自动自定义的方法就好)


画UI这个没啥好说的,代码上我也写了注释,我就直接贴代码吧


我没有完全自定义tabBarController,而是继承了系统的UITabBarController,然后用kvc的方式把自定的tabBar替换掉系统自带的UITabBar,这样做的好处就是,保留下了原生tabBarController的所有功能以及代理方法。因为原生tabBar是readOnly的,所以要用kvc的方法来替换,方法很简单,直接看代码吧,在RootViewController上

至此,UITabBar也自定义完成了。

      接下来,我们再做一下sideMenu,现在很多app都是有这个sideMenu的,sideMenu算是一种比较优雅而且便捷的方式来增加app的平行分支。sideMenu就是一个tableView,本人觉得最好是在RootViewController上面弹出,这样做的好处是随时随地都可以通过响应链来到RootViewController弹出这个sideMenu。然后在segue上自定义一下弹出的动画就行了,这个比较简单,效果大概如下:


现在,关键的问题来了,因为我们现在的主界面是tabBarController,当sideMenu上的分支多于tabBarController上的tabBarItem的时候(这不是废话嘛,肯定是多于的,不然要个sideMenu有嘛用呢),怎样切换sideMenu上的分支呢,这是一个关键问题,也是一个难点。我思考过几种方案,也参考过别人做的sideMenu,得出一种还算比较可以的方法,因为我们的架构是tabBarController上每个tabBarItem嵌套一个UINavigationController,所以我们可以拿到这个navigationController,用这个navigationController去push sideMenu上的其它分支。这样我们就可以不用更换app的rootViewController,还是一个整体,MainViewController还是tabBarController,只是我们点击sideMenu上其它分支的时候,我们利用当前tabBarItem上的navigationController去push 出这些分支。我们可以通过这样的方法拿到当前tabBarItem上的navigationController


至此,sideMenu也做完了。整体的架构效果就像QQ的差不多了。QQ上点击sideMenu之后push出的分支是隐藏tabBar的,但是,我不想隐藏呢,这时就会有一个小问题,因为我们是通过当前选中的tabBarItem上的navigationController来push出sideMenu的分支的,那么此时被选中的tabBarItem会一直高亮,这看起来就怪怪的了,明明没有选中这个分支,但是这个分支却高亮。为了完善这个细节,本人查找了很多资料,也看了一些别人sideMenu的效果,很多基本都是存在这个问题的,恕本人学浅,目前我找到的解决方法就是,在点击sideMenu分支的时候,把所有tabBarItem的selectedImage替换成非选中状态下同样的图片,把tintColor也替换成非选中状态下的color,这样虽然实际上tabBarController是有一个selectedIndex的,但是,因为我们在切换成sideMenu分支的时候同时把tabBar的selectedImage以及tintColor都换成了非选中状态下同样的,表面看起来就像是所有tabBarItem都没有被选中的样子,然后当我们点击tabBarItem的时候,再把tabBarItem的selectedImage tintColor换回来选中状态的,这样就可以在表面上解决上面一直高亮这个问题了(如果哪位大神有更好的方法,望赐教)。具体的实现方式是这样的,直接看代码,在RootViewController上


点击sideMenu上的分支的时候调用这个方法就可以了。然后再实现UITabBarController的两个delegate方法完善一些小细节


    至此,整个架构就搭建完成了(当然,关于上面的tabBarItem一直高亮这个问题,也可以通过自定义tabBarController来解决,自定义的tabBarController不再继承UITabBarController,而是继承UIViewController,自己写切换tabBarItem的方法,这种方法,我将会在另外一篇文章中去探讨)。

    行文至此,iOS项目的基本架构就搭建完成了,就是一个RootViewController作为app的rootViewController,在rootViewController上Embed一个tabBarController,在每个tabBarItem上嵌套一个UINavigationController,然后再做一个sideMenu,就完成了。具体效果看下图:


这是一个通用的,市面上大部分app都在使用的基本架构。这篇文字是写给小白们和初级开发人员们的,大神们肯定有自己成熟的架构,也不屑于看这样的小白文章,没必要,当然,这篇文章也是写给自己的,作为自己工作的一些记录,也是鞭策自己多去写技术文章,多去总结经验。

    行文至此,我还是那句老话,如果文章能给读者带来一丝帮助或启发,我就觉得是一件幸事了。

    demo放在GitLab上了

猜你喜欢

转载自blog.csdn.net/pbz106/article/details/79013503