ios架构篇-view层

大部分系统、大部分的架构模式,都使用MVC。MVVM、MVP等模式,本质上都是对MVC的演变。ios架构,也是如此。在移动领域,app中v和c都非常容易区分,最重要的是controller这层。往往我们觉得不像v、也不像c的东西,就直接放到controller里面,最直接的结果就是造成controller庞大、复杂,不容易维护,平时迭代升级还好,如果遇到较大的需求变更或者迭代次数变多,就会变得很困难。本人就有非常深的体验。所以要研究app的架构,帮助我们解决问题。

首先,一个架构并不是固定的,但是好的架构总是有那么几点是相同的,不能只抄形,而学不到神。没有绝对好的架构,只有最适合的架构,只有最好的架构师。view层架构是影响工程师迭代周期重要因素之一。加班不是优化迭代周期的正确方式。一般来说,一个不够好的view层架构,主要原因有以下5种:

  1. 代码混乱不规范
  2. 过多继承导致的复杂依赖关系
  3. 模块化程度不够高,组件粒度不够细
  4. 横向依赖
  5. 架构设计失去传承

      这5个地方是会影响工程师实现需求的效率,进而拖慢迭代周期。当然view架构的其他缺陷会或多或少的产生影响,但在我看来这5个是比较重要的因素。对于第5点要说明一下,架构的设计是一定需要传承的。但实际的情况可能是一个核心的人走了,另一个人顶上,即便任务交接的再完整,都不可避免不同的人有不同的架构思路,从而导致整个架构的流程受到影响。要解决这个问题,要做到2点,首先做架构的时候最好带上一个人,其次是架构尽可能的简单,平缓接手人的学习曲线。当一个大牛从公司立刻的时候,可以说:从我手里出来的代码,终身保修。所以不要想着离职了,就没我什么事了,这不光是职业素养的问题,更是一个人对自己代码是否有足够的自信。传承性对于view层架构非常重要,因为它距离业务最近,改动余地最小。view层跟业务的对接面最广,影响业务层代码的程度也最深,在view架构上牵一发导致业务层动全身面积最大。所以view层架构在所有架构中一旦定型,可修改的空间就最小。我们在考虑view层架构的时候,不光要实现功能,还要考虑更多规范上的东西。制定规范的目的,一方面是防止代码腐蚀view架构,另一方面也是想有所传承。按照规范来,不那么容易出差池。规范也不是一成不变的,大家会提一些意见,什么时候枪毙意见,什么时候采纳意见,就要靠各自的技术和经验了。

view结构代码的规定

严格来讲,制定代码规范不属于view层架构的事情,但它对view层架构未来的影响会很大,所以在设计view架构的时候必须考虑。制定view层规范的重要性在于:

1、提高业务代码的可维护性和可扩展性。

2、防止业务代码对架构产生腐蚀。

3、确保传承。

4、保持架构发展的放心不容易被不合理的意见左右。

代码定义的规范,苹果已经有一套。

建议在规范上再加上下面这一点。

viewcontroller的代码差不多应该是这样:

@property (nonatomic, weak) IBOutlet NSLayoutConstraint *lcCommentsNumWidth;
...

#pragma mark - life cycle
viewDidLoad
viewWillAppear

#pragma mark - UITableViewDelegate
methods

#pragma mark - CustomDelegate
methods

#pragma mark - event response
-(IBAction)onClick:(id)sender

#pragma mark - private methods
methods

#pragma mark - getters and setters
- (UIButton *)confirmButton

所有属性都使用getter和setter。

不要在viewDidLoad里初始化你的view然后再add,这样代码就很难看。在viewDidLoad里面只做addSubview的事情,然后在viewWillAppear里面做布局的事情,最后在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:NO];
    [self.firstFilterLabel top:10 FromView:self.originImageView];

    ... ...
}
这样即便在属性非常多的情况下,还能保持代码整齐,view的初始化都交给getter去做了。总之就是尽量不要出现以下情况:
- (void)viewDidLoad
{
    [super viewDidLoad];

    self.textLabel = [[UILabel alloc] init];
    self.textLabel.textColor = [UIColor blackColor];
    self.textLabel ... ...
    self.textLabel ... ...
    self.textLabel ... ...
    [self.view addSubview:self.textLabel];
}

这种做法就不够干净,都扔到getter里面去好了。

每一个Delegate都把对应的protocol名字带上,delegate方法不要到处乱写,写到一块区域里面去。

比如,UITableViewDelegate的方法集就老老实实写上#pragma mark - UITableViewDelegate。这样有个好处就是,当其他人阅读他并不熟悉的Delegate方法时,能够快速的找到。

event response专门开一个代码区域

所有button、gestureRecognizer的响应事件都放在这个区域里,不要到处乱放。

关于private methods,正常情况下viewcontroller里面不应该有

不是delegate方法,不是event response方法,不是life cycle方法,就是private methods了。对的,正常情况下viewcontroller里面一般是不会存在private methods的,这个private methods一般是用于日期推算、图片裁剪啥的这种小功能。这种小功能要么把它写成一个category,要么把他做成一个模块,哪怕这个模块只有这一个函数也行。

viewcontroller基本上是大部分业务的载体,本身代码已经相当复杂,所以跟业务关联不大的东西能不放viewcontroller就不放。另外,private methods的功能这时候只是你用的到,但是将来说不定其他其他也会用,一开始就独立出来,有利于将来代码的复用。





阅读更多
个人分类: IOS
所属专栏: iOS架构
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭