一 、什么是DSL
DSL(Domain Specific Language) 翻译成中文就是:“领域特定语言”。首先,从定义就可以看出,DSL 也是一种编程语言,只不过它主要是用来处理某个特定领域的问题。
下边介绍iOS中如何实现链式调用的DSL。
二、具体实现
首先我们经常使用的**Masonry**便是这样处理的,下边一段代码:
// Masonry
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superview.mas_top).with.offset(padding.top);
make.left.equalTo(superview.mas_left).with.offset(padding.left);
make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];
更加简洁的,我们可以将中括号去掉,直接通过不间断的点语法来实现。
实现DSL的基本思想就是通过block传递需要的参数,并且返回对象本身,从而进一步点语法调用下一个属性。(返回本身就是写出属性的getter方法,通过例子可以很好地明白)。
在iOS中实现DSL,基本上实现三部分:
(1).首部创建
(2).中间的连接属性
(3).结尾返回
咱们实现一个UIButton的DSL,包含部分属性。我们经常使用的控件等都可以封装成这种DSL,可以方便我们使用。先看下边的这段代码:
[self.view addSubview: UIButton.
creatButton.
buttonUtil.
titl(@"aaaa", UIControlStateNormal).
frame(CGRectMake(10, 10, 200, 200)).
buttonTyp(UIButtonTypeCustom)];
上述代码中的creatButton就是咱们的创建首部,中间的titl、frame就是中间的连接属性,buttonTyp就是结尾返回。
<1> 首先继承NSObject,将button的属性用block重写
#import <UIKit/UIKit.h>
@interface ButtonUtil : NSObject
/**
通过Block传递需要的参数,然后返回值是ButtonUtil,可以继续调用下一个属性
*/
@property(nonatomic, weak,readonly)ButtonUtil * (^contentEdgInset)(UIEdgeInsets *contentEdgeInset);
@property(nonatomic, weak,readonly)ButtonUtil * (^showsTouchWhenHighlighte)(BOOL showsTouchWhenHighlighte);
@property(nonatomic, weak,readonly)ButtonUtil * (^tintColo)(UIColor * tintColo);
@property(nonatomic, weak,readonly)ButtonUtil * (^titl)(NSString * title, UIControlState state);
@property(nonatomic, weak,readonly)ButtonUtil * (^titleColo)(UIColor * color, UIControlState state);
@property(nonatomic, weak,readonly)ButtonUtil * (^shadowColo)(UIColor * color, UIControlState state);
@property(nonatomic, weak,readonly)ButtonUtil * (^imag)(UIImage * image, UIControlState state);
@property(nonatomic, weak,readonly)ButtonUtil * (^backgroundImag)(UIImage * image, UIControlState state);
@property(nonatomic, weak,readonly)ButtonUtil * (^attributeTitle)(NSAttributedString * title, UIControlState state);
@property(nonatomic, weak,readonly)ButtonUtil * (^frame)(CGRect rect);
/**
结尾属性,返回值是UIButton,完成一个button的创建
*/
@property(nonatomic, weak,readonly)UIButton * (^buttonTyp)(UIButtonType typ);
@end
下边是.m文件的实现(没有全部实现仅仅是举例)
@interface ButtonUtil()
@property(nonatomic,strong)UIButton *button;
@end
@implementation ButtonUtil
-(ButtonUtil *(^)(CGRect))frame
{
return ^(CGRect frame)
{
self.button.frame =frame;
return self;
};
}
-(ButtonUtil *(^)(NSString *, UIControlState))titl
{
return ^(NSString * str ,UIControlState state)
{
[self.button setTitle:str forState:state];
return self;
};
}
-(UIButton *(^)(UIButtonType))buttonTyp{
return ^(UIButtonType type){
return self.button;
};
}
@end
<2>创建一个UIbutton的类别,来实现首部的创建,可以使用button直接调用创建button的方法
@interface UIButton (utils)
@property(nonatomic,strong ,readonly) ButtonUtil * buttonUtil;
@property(class, nonatomic ,strong,readonly) UIButton * creatButton;
@implementation UIButton (utils)
static ButtonUtil *_maker = nil;
-(ButtonUtil *)buttonUtil{
return _maker;
}
+(UIButton *)creatButton
{
ButtonUtil * util =[[ButtonUtil alloc]init];
_maker = util;
_maker.button = [[UIButton alloc]init];
return _maker.button;
}
@end
在<1>中创建中间变量,返回的是ButtonUtil本身,可以继续调用其他属性;创建尾部结束语,返回的是UIbutton。
三、总结
(1)、基本上所有的控件都可以重新封装。
(2)、分开两个类优点就是清晰,谁的事谁干,可以防止.buttonUtil.buttonUtil.buttonUtil.buttonUtil这种。
(3)、这种链式调用能够使程序更加清晰,在特定场景下使程序的可读性更强。
还会逐步更改,写的时候有的地方感觉不是很连贯。可以参考代码一起看。链接地址:https://github.com/rainhand/iOS-DSL-chaine.git