前言html
《iOS应用架构谈 开篇》出来以后,不少人来催我赶忙出第二篇。这一篇文章出得至关艰难,由于公司里的破事儿特别多,我本身又有点私事儿,以致于能用来写博客的时间不够充分。java
如今好啦,第二篇出来了。react
当咱们开始设计View层的架构时,每每是这个App尚未开始开发,或者这个App已经发过几个版本了,而后此时须要作很是完全的重构。ios
通常也就是这两种时机会去作View层架构,基于这个时机的特殊性,咱们在这时候必须清楚认识到:View层的架构一旦实现或定型,在App发版后可修改的余地就已经很是之小了。由于它跟业务关联最为紧密,因此哪怕稍微动一点点,它所引起的蝴蝶效应都不见得是业务方可以hold住的。这样的状况,就要求咱们在实现这个架构时,代码必须得改得勤快,不能偷懒。也必须抱着充分的自我怀疑态度,作决策时要拿捏好尺度。git
View层的架构很是之重要,在我看来,这部分架构是这系列文章涉及4个方面最重要的一部分,没有之一。为何这么说?程序员
View层架构是影响业务方迭代周期的因素之一github
产品经理产生需求的速度会很是快,尤为是公司此时仍处于创业初期,在规模稍大的公司里面,产品经理也喜欢挖大坑来在leader面前刷存在感,好比阿里。这就致使业务工程师任务很是繁重。正常状况下让产品经理砍需求是不太可能的,所以做为架构师,在架构里有一些可作可不作的事情,最好仍是能作就作掉,不要偷懒。这能够帮业务方减负,编写代码的时候也能更加关注业务。web
我跟一些朋友交流的时候,他们都会或多或少地抱怨本身的团队迭代速度不够快,或者说,迭代速度不合理地慢。我认为迭代速度不是想提就能提的,迭代速度的影响因素有不少,一期PRD里的任务量和任务复杂度都会影响迭代周期能达到什么样的程度。抛开这些外在的不谈,从内在可能致使迭代周期达不到合理的速度的缘由来看,其中有一个缘由颇有可能就是View层架构没有作好,让业务工程师完成一个不算复杂的需求时,须要处理太多额外的事情。固然,开会多,工程师水平烂也属于迭代速度提不上去的内部缘由,但这个不属于本文讨论范围。还有,加班不是优化迭代周期的正确方式
,嗯。面试
通常来讲,一个不够好的View层架构,主要缘由有如下五种:数据库
- 代码混乱不规范
- 过多继承致使的复杂依赖关系
- 模块化程度不够高,组件粒度不够细
- 横向依赖
- 架构设计失去传承
这五个地方会影响业务工程师实现需求的效率,进而拖慢迭代周期。View架构的其余缺陷也会或多或少地产生影响,但在我看来这里五个是比较重要的影响因素。若是你们以为还有什么因素比这四个更高的,能够在评论区提出来我补上去。
对于第五点我想作一下强调:架构的设计是必定须要有传承的,有传承的架构从总体上看会很是协调。但实际状况有多是一我的走了,另外一个顶上,即使任务交接得再完整,都不可避免不一样的人有不一样的架构思路,从而致使整个架构的流畅程度受到影响。要解决这个问题,一方面要尽可能避免单点问题,让架构师作架构的时候再带一我的。另外一方面,架构要设计得尽可能简单,平缓接手人的学习曲线。我离开安居客的时候,作过保证:凡是从我手里出来的代码,终身保修
。因此不要想着离职了就什么事儿都无论了,这不光是职业素养问题,还有一个是你对你的代码是否足够自信的问题。传承性对于View层架构很是重要,由于它距离业务最近,改动余地最小。
因此当各位CTO、技术总监、TeamLeader们以为迭代周期不够快时,你能够先不忙着急吼吼地去招新人,《人月神话》早就说过加人不能彻底解决问题。这时候若是你能够回过头来看一下是否是View层架构不合理,把这个弄好也是优化迭代周期的手段之一。
嗯,至于本系列其余三项的架构方案对于迭代周期的影响程度,我认为都不如View层架构方案对迭代周期的影响高,因此这是我认为View层架构是最重要的其中一个理由。
View层架构是最贴近业务的底层架构
View层架构虽然也算底层,但还没那么底层,它跟业务的对接面最广,影响业务层代码的程度也最深。在全部的底层都牵一发的时候,在View架构上牵一发致使业务层动全身的面积最大。
因此View架构在全部架构中一旦定型,可修改的空间就最小,咱们在一开始考虑View相关架构时,不光要实现功能,还要考虑更多规范上的东西。制定规范的目的一方面是防止业务工程师的代码腐蚀View架构,另外一方面也是为了可以有所传承。按照规范来,总仍是不那么容易出差池的。
还有就是,架构师一开始考虑的东西也会有不少,不可能在初版就把它们所有实现,对于一个还没有发版的App来讲,初版架构每每是最小完整功能集,那么在第二版第三版的发展过程当中,架构的迭代任务就颇有可能不仅是你一我的的事情了,相信你一我的也不见得能搞定所有。因此你要跟你的合做者们有所约定。另外,初版出去以后,业务工程师在使用过程当中也会产生不少修改意见,哪些意见是合理的,哪些意见是不合理的,也要经过事先约定的规范来进行筛选,最终决定如何采纳。
规范也不是一成不变的,何时枪毙意见,何时改规范,这就要靠各位的技术和经验了。
以上就是前言。
这篇文章讲什么?
-
View代码结构的规定
-
关于view的布局
-
什么时候使用storyboard,什么时候使用nib,什么时候使用代码写View
-
是否有必要让业务方统一派生ViewController?
-
方便View布局的小工具
-
MVC、MVVM、MVCS、VIPER
-
本门心法
-
跨业务时View的处理
-
留给评论区各类补
-
总结
View代码结构的规定
架构师不是写SDK出来交付业务方使用就没事儿了的,每家公司必定都有一套代码规范,架构师的职责也包括定义代码规范。按照道理来说,定代码规范应该是属于通识,放在这里讲的缘由只是由于我这边须要为View添加一个规范。
制定代码规范严格来说不属于View层架构的事情,但它对View层架构将来的影响会比较大,也是属于架构师在设计View层架构时须要考虑的事情。制定View层规范的重要性在于:
- 提升业务方View层的可读性可维护性
- 防止业务代码对架构产生腐蚀
- 确保传承
- 保持架构发展的方向不轻易被不合理的意见所左右
在这一节里面我不打算从头开始定义一套规范,苹果有一套Coding Guidelines,当咱们定代码结构或规范的时候,首先必定要符合这个规范。
而后,相信你们各自公司里面也都有一套本身的规范,具体怎么个规范法其实也是根据各位架构师的经验而定,我这边只是建议各位在各自规范的基础上再加上下面这一点。
viewController的代码应该差很少是这样:
要点以下:
全部的属性都使用getter和setter
不要在viewDidLoad里面初始化你的view而后再add,这样代码就很难看。在viewDidload里面只作addSubview的事情,而后在viewWillAppear里面作布局的事情(勘误1
),最后在viewDidAppear里面作Notification的监听之类的事情。至于属性的初始化,则交给getter去作。
好比这样:
#pragma mark - life cycle
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; [self.view addSubview:self.firstTableView]; [self.view addSubview:self.secondTableView]; [self.view addSubview:self.firstFilterLabel]; [self.view addSubview:self.secondFilterLabel]; [self.view addSubview:self.cleanButton]; [self.view addSubview:self.originImageView]; [self.view addSubview:self.processedImageView]; [self.view addSubview:self.activityIndicator]; [self.view addSubview:self.takeImageButton]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; CGFloat width = (self.view.width - 30) / 2.0f; self.originImageView.size = CGSizeMake(width, width); [self.originImageView topInContainer:70 shouldResize:NO]; [self.originImageView leftInContainer:10 shouldResize:NO]; self.processedImageView.size = CGSizeMake(width, width); [self.processedImageView right:10 FromView:self.originImageView]; [self.processedImageView topEqualToView:self.originImageView]; CGFloat labelWidth = self.view.width - 100; self.firstFilterLabel.size = CGSizeMake(labelWidth, 20); [self.firstFilterLabel leftInContainer:10 shouldResize