题目中引人注目的感叹号,在这句话的作用不是惊讶,而表达的是,应该这样做。为所有视图建立基类,利用继承和多态的特性,更好地约束视图类的代码和风格。

从代码入手

.h文件的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import <UIKit/UIKit.h>
@protocol NTBasicViewProtocol <NSObject>
- (void)setUpSubViews;
- (void)setUpConstraints;
@optional
- (void)bindViewModel;
@end
@interface NTBasicView : UIView <NTBasicViewProtocol>
@end

为了更清晰地看到到代码,这里没有在代码中添加注释。那么现在就来看下代码.h文件中的代码组成,声明了NTBasicViewProtocol这个协议,协议中有两个必须实现的方法

  • setUpSubViews:设置子控件
  • setUpConstraints:设置子控件的约束(位置)

以及一个可选实现的方法

  • bindViewModel:事件绑定方法

了解了头文件声明了哪些方法之后,我们需要知道基类的实现

.m文件的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#import "NTBasicView.h"
@implementation NTBasicView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// 多态性
[self setUpSubViews];
[self setUpConstraints];
[self bindViewModel];
// 共性定制
[self setUpCommonness];
}
return self;
}
#pragma mark - Inner Method
- (void)setUpCommonness
{
}
#pragma mark - Override Method
- (void)setUpSubViews
{
}
- (void)setUpConstraints
{
}
- (void)bindViewModel
{
}
@end

代码很简单,但是要设计好基类,就需要了解继承和多态的特性。可以发现,在重写的初始化方法中,执行了协议中声明的是三个方法,以及一个内部方法

  • 协议声明的方法
    由于基类实现了协议,所以需要实现方法,但是可以发现实现方法中没有任何代码,这是因为这些方法都是为多态性来准备的,来看看这几个方法的目的:设置子视图,设置子视图约束,设置事件绑定。不难知道,这类的方法的实现内容对于每个视图都不尽相同,所以基类只提供一个空壳,留给子类去重写。同时,这些方法在基类重写的初始化方法中执行,所以子类不用关系这几个方法的调用时机,只需要放心地关心业务逻辑即可。那么调用是在何时发生的呢?当子类初始化的时候,会调用基类的初始化方法,在基类的初始化方法中又会调用子类重写的这几个协议方法。
  • 内部方法
    内部方法没有定义在协议或者是说头文件中,所以子类也无法去重写它,那么它的作用就是封装一些视图共性,不同的项目,可能会有不同的视图需求,那么将所有视图的共性抽出,封装在该方法即可。