链式编程

链式编程:将多个操作通过点号(.)链接在一起成为一句代码,代表作:用OC写的masonry框架
我们平时编码习惯是把事情封装到一个方法中。而链式编程思想则是把要做的事情封装到block,给外界提供一个返回这个Block的方法
链式编程思想方法的特点:
(1)方法的返回值必须是block
(2)block参数:放需要操作的内容
(3)block返回值:方法调用者
链式编程的优点:增加代码可读性,利用block的特点使代码高聚合

示例:实现简易计算器
1、创建计算制造者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@interface CaculatorMaker : NSObject
@property (nonatomic, assign) int result;
- (CaculatorMaker *(^)(int num))add;
- (CaculatorMaker *(^)(int num))multy;
@end
@implementation CaculatorMaker
- (CaculatorMaker *(^)(int num))multy
{
return ^(int num){
_result *= num;
return self;
};
}
- (CaculatorMaker * (^)(int num))add
{
return ^(int num){
_result += num;
return self;
};
}
@end

2、给NSObject增加一个分类方法

1
2
3
4
5
6
7
8
9
10
11
12
@interface NSObject (Caculator)
+ (int)makeCaculator:(void(^)(CaculatorMaker *))block;
@end
@implementation NSObject (Caculator)
+ (int)makeCaculator:(void (^)(CaculatorMaker *))block
{
CaculatorMaker *maker = [[CaculatorMaker alloc] init];
block(maker);
return maker.result;
}
@end

3、外界调用

1
2
3
4
5
6
7
int result = [NSObject makeCaculator:^(CaculatorMaker *maker) {
maker.add(10).add(20);
maker.add(30).add(40);
maker.multy(3).add(5);
maker.multy(4);
}];
NSLog(@"%d",result);

Swift中体验链式编程

链式代码在 Swift 中有着比 Objective-C 天然的优势
以下部分摘录自webfrogs写的Swift 实践篇之链式 UI 代码
1、避免命名冲突
由于是对UIView做的方法扩展,所以存在命名冲突的隐患。所以先为方法定义一个个性前缀 xr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import Foundation
public protocol NamespaceWrappable {
associatedtype XRWrapperType
var xr: XRWrapperType { get }
static var xr: XRWrapperType.Type { get }
}
public extension NamespaceWrappable {
var xr: NamespaceWrapper<Self> {
return NamespaceWrapper(value: self)
}
static var xr: NamespaceWrapper<Self>.Type {
return NamespaceWrapper.self
}
}
public struct NamespaceWrapper<T> {
public let wrappedValue: T
public init(value: T) {
self.wrappedValue = value
}
}

2、给UIView的子类做链式支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import UIKit
import SnapKit
extension UIView: NamespaceWrappable { }
extension NamespaceWrapper where T: UIView {
public func adhere(toSuperView: UIView) -> T {
toSuperView.addSubview(wrappedValue)
return wrappedValue
}
@discardableResult
public func layout(snapKitMaker: (ConstraintMaker) -> Void) -> T {
wrappedValue.snp.makeConstraints { (make) in
snapKitMaker(make)
}
return wrappedValue
}
@discardableResult
public func config(_ config: (T) -> Void) -> T {
config(wrappedValue)
return wrappedValue
}
}

config 函数的闭包参数在实际使用中,闭包的第一个参数类型可以具体到 UIView 的不同子类上。

实例调用

1
2
3
4
5
6
7
8
9
10
11
12
13
releaseBtn = UIButton(type: .custom)
.xr.adhere(toSuperView: view)
.xr.layout { make in
make.width.height.equalTo(40)
make.right.bottom.equalToSuperview().offset(-15)
}
.xr.config{ btn in
btn.setTitle("发布", for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
btn.layer.cornerRadius = 20
btn.layer.masksToBounds = true
btn.backgroundColor = kThemeColor
}

也可以灵活抽取config共用部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let btnConfiger = { (btn: UIButton) in
btn.setTitle("发布", for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 15)
btn.layer.cornerRadius = 20
btn.layer.masksToBounds = true
btn.backgroundColor = kThemeColor
}
releaseBtn = UIButton(type: .custom)
.xr.adhere(toSuperView: view)
.xr.layout { make in
make.width.height.equalTo(40)
make.right.bottom.equalToSuperview().offset(-15)
}
.xr.config(btnConfiger)
// 覆盖标题
releaseBtn.xr.config { (btn) in
btn.setTitle("啦啦", for: .normal)
}
releaseBtn.setTitle("安慰", for: .normal)

Swift和OC混用的链式UI编程实践

旧项目里的OC一下子不能迁移到Swift上,可以先在新需求上使用Swift编码
1、先做好OC与Swift混编设置
2、因为旧项目里使用的是Masonry框架做自动布局,所以只需改动一下上文中NamespaceWrapper协议扩展里的layout方法即可

1
2
3
4
5
6
7
@discardableResult
public func layout(masonryMaker: (MASConstraintMaker!) -> Void) -> T {
wrappedValue.mas_makeConstraints { (make) in
masonryMaker(make)
}
return wrappedValue
}

3、链式UI编码实践调用

1
2
3
4
5
6
7
8
9
10
let bgV = UIView()
.xr.adhere(toSuperView: view)
.xr.layout { (make) in
make.top.mas_equalTo()(view)?.offset()(15)
make.left.right().mas_equalTo()(view)
make.height.equalTo()(88)
}
.xr.config { (bgView) in
bgView.backgroundColor = UIColor.white
}

打赏支持一下呗!