链式编程最难得地方是想通,实现是如此的简单:
例一: UIAlertController弹窗
🌰🌰:
func showAlert() {
UIAlertController(title: "提示", message: "信息", preferredStyle: .alert)
.addActionTitle(kTitleSure, style: .default) { (action) in
DDLog(action.title)
}
.addActionTitle(kTitleCancell, style: .destructive) { (action) in
DDLog(action.title)
}
.addTextFieldPlaceholder("", handler: { (textfield) in
DDLog(textfield.text)
}).present {
DDLog("present")
}
}
@objc public extension UIAlertController {
///添加 UIAlertAction
func addActionTitle(_ title: String?, style: UIAlertAction.Style, handler: ((UIAlertAction) -> Void)? = nil) -> UIAlertController {
self.addAction(UIAlertAction(title: title, style: style, handler: handler))
return self
}
///添加多个 UIAlertAction
func addActionTitles(_ titles: [String]?, handler: ((UIAlertAction) -> Void)? = nil) -> UIAlertController {
titles?.forEach({ (string) in
let style: UIAlertAction.Style = string == "取消" ? .destructive : .default
self.addAction(UIAlertAction(title: string, style: style, handler: handler))
})
return self
}
///添加 textField
func addTextFieldPlaceholder(_ placeholder: String, handler: ((UITextField) -> Void)? = nil) -> UIAlertController {
self.addTextField { (textField: UITextField) in
textField.placeholder = placeholder
handler?(textField)
}
return self
}
}
@objc public extension UIViewController {
///展示
public func present(_ animated: Bool = true, completion: (() -> Void)? = nil) {
guard let keyWindow = UIApplication.shared.keyWindow,
let rootVC = keyWindow.rootViewController
else { return }
DispatchQueue.main.async {
if let alertVC = self as? UIAlertController {
if alertVC.preferredStyle == .alert {
if alertVC.actions.count == 0 {
rootVC.present(alertVC, animated: animated, completion: {
DispatchQueue.main.after(TimeInterval(kDurationToast), execute: {
alertVC.dismiss(animated: animated, completion: completion)
})
})
} else {
rootVC.present(alertVC, animated: animated, completion: completion)
}
} else {
//防止 ipad 下 sheet 会崩溃的问题
if UIDevice.current.userInterfaceIdiom == .pad {
if let popoverPresentationController = alertVC.popoverPresentationController {
popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
popoverPresentationController.sourceView = keyWindow;
let isEmpty = popoverPresentationController.sourceRect.equalTo(.null) || popoverPresentationController.sourceRect.equalTo(.zero)
if isEmpty {
popoverPresentationController.sourceRect = CGRect(x: keyWindow.bounds.midX, y: 64, width: 1, height: 1);
}
}
}
rootVC.present(alertVC, animated: animated, completion: completion)
}
} else {
rootVC.present(self, animated: animated, completion: completion)
}
}
}
///判断上一页是哪个页面
public func pushFromVC(_ type: UIViewController.Type) -> Bool {
guard let viewControllers = navigationController?.viewControllers else {
return false }
if viewControllers.count
例二:圆角阴影

链式圆角阴影效果图.jpg
🌰🌰:
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setTitle:@"UIButton" forState:UIControlStateNormal];
[btn setTitleColor:UIColor.systemBlueColor forState:UIControlStateNormal];
[self.view addSubview:btn];
btn.nn_borderWidth(1).nn_borderColor(UIColor.systemBlueColor).
conrnerRadius(5).
nn_shadowColor(UIColor.redColor).nn_shadowOpacity(0.8).nn_shadowOffset(CGSizeZero).nn_shadowRadius(5);
btn.frame = CGRectMake(20, 110, 100, 40);
/*
方法 swift 报错;
添加前缀是为了防止和其他视图参数冲突
*/
#import
NS_ASSUME_NONNULL_BEGIN
@interface UIView (Chain)
/// 圆角半径 默认 0.0
@property(nonatomic, strong, readonly) UIView *(^nn_conrnerRadius)(CGFloat value);
/// 边框颜色 默认 black
@property(nonatomic, strong, readonly) UIView *(^nn_borderColor)(UIColor *value);
/// 边框宽度 默认 0.0
@property(nonatomic, strong, readonly) UIView *(^nn_borderWidth)(CGFloat value);
/// 阴影
/// 阴影(颜色 默认 black, 半径, 模糊度 (0~1] 默认 0.0, 偏移方向和距离 默认 {0.0,0.0})
@property(nonatomic, strong, readonly) UIView *(^nn_shadow)(UIColor *color, CGFloat radius, CGFloat opacity, CGSize offset);
/// 阴影颜色 默认 black
@property(nonatomic, strong, readonly) UIView *(^nn_shadowColor)(UIColor *value);
/// 阴影模糊度 默认 0.0
@property(nonatomic, strong, readonly) UIView *(^nn_shadowRadius)(CGFloat value);
/// (0~1] 默认 0.0
@property(nonatomic, strong, readonly) UIView *(^nn_shadowOpacity)(CGFloat value);
/// 阴影偏移方向和距离 默认 {0.0,0.0}
@property(nonatomic, strong, readonly) UIView *(^nn_shadowOffset)(CGSize value);
/// 图层
@property(nonatomic, strong, readonly) UIView *(^nn_zPosition)(CGFloat value);
@end
#import "UIView+Chain.h"
@implementation UIView (Chain)
- (UIView * _Nonnull (^)(CGFloat))nn_conrnerRadius{
return ^(CGFloat value){
self.layer.cornerRadius = value;
return self;
};
}
- (UIView * _Nonnull (^)(UIColor * _Nonnull))nn_borderColor{
return ^(UIColor *value){
self.layer.borderColor = value.CGColor;
return self;
};
}
- (UIView * _Nonnull (^)(CGFloat))nn_borderWidth{
return ^(CGFloat value){
self.layer.borderWidth = value;
return self;
};
}
- (UIView * _Nonnull (^)(UIColor * _Nonnull, CGFloat, CGFloat, CGSize))nn_shadow{
return ^(UIColor *color, CGFloat radius, CGFloat opacity, CGSize offset){
self.layer.shadowColor = color.CGColor;
self.layer.shadowRadius = radius;
self.layer.shadowOpacity = opacity;
self.layer.shadowOffset = offset;
return self;
};
}
- (UIView * _Nonnull (^)(UIColor * _Nonnull))nn_shadowColor{
return ^(UIColor *value){
self.layer.shadowColor = value.CGColor;
return self;
};
}
- (UIView * _Nonnull (^)(CGFloat))nn_shadowOpacity{
return ^(CGFloat value) {
self.layer.shadowOpacity = value;
return self;
};
}
- (UIView * _Nonnull (^)(CGFloat))nn_shadowRadius{
return ^(CGFloat value) {
self.layer.shadowRadius = value;
return self;
};
}
- (UIView * _Nonnull (^)(CGSize))nn_shadowOffset{
return ^(CGSize value) {
self.layer.shadowOffset = value;
return self;
};
}
- (UIView * _Nonnull (^)(CGFloat))nn_zPosition{
return ^(CGFloat value){
self.layer.zPosition = value;
return self;
};
}
@end
例三:计算器加减乘除
let cal = Calculator()
cal.add(5).add(8).print().multiply(2).print().divide(3).print()
2020-09-06 22:13:36.770 SwiftTemplet[18682:14020939] 计算结果: 13
2020-09-06 22:13:36.771 SwiftTemplet[18682:14020939] 计算结果: 26
2020-09-06 22:13:36.771 SwiftTemplet[18682:14020939] 计算结果: 8.666666666666666
#import
NS_ASSUME_NONNULL_BEGIN
@interface Calculator : NSObject
//计算结果
@property(nonatomic, assign) CGFloat result;
///在结果上加
@property(nonatomic, strong, readonly) Calculator *(^add)(CGFloat);
///在结果上减
@property(nonatomic, strong, readonly) Calculator *(^sub)(CGFloat);
///在结果上乘
@property(nonatomic, strong, readonly) Calculator *(^multiply)(CGFloat);
///在结果上除
@property(nonatomic, strong, readonly) Calculator *(^divide)(CGFloat);
///清零
-(Calculator *)clear;
///打印结果
-(Calculator *)print;
@end
NS_ASSUME_NONNULL_END
#import "Calculator.h"
@implementation Calculator
-(instancetype)init{
if (self = [super init]) {
self.result = 0;
}
return self;
}
-(Calculator *(^)(CGFloat))add{
return ^(CGFloat value){
self.result += value;
return self;
};
}
-(Calculator *(^)(CGFloat))sub{
return ^(CGFloat value){
self.result -= value;
return self;
};
}
- (Calculator * _Nonnull (^)(CGFloat))multiply{
return ^(CGFloat value){
self.result *= value;
return self;
};
}
- (Calculator * _Nonnull (^)(CGFloat))divide{
return ^(CGFloat value){
self.result /= value;
return self;
};
}
-(Calculator *)clear{
self.result = 0;
return self;
}
-(Calculator *)print{
NSLog(@"计算结果: %@n", @(self.result));
// NSLog(@"计算结果:%.2fn", self.result);
return self;
}
@end
仿 Masonry
#import "Calculator.h"
NS_ASSUME_NONNULL_BEGIN
@interface Calculator (Chain)
+ (CGFloat)nn_makeCalcuclate:(void(^)(Calculator *))block;
@end
NS_ASSUME_NONNULL_END
#import "Calculator+Chain.h"
@implementation Calculator (Chain)
+ (CGFloat)nn_makeCalcuclate:(void(^)(Calculator *))block{
Calculator *manager = [[Calculator alloc] init];
block(manager);
return manager.result;
}
@end
例四:OC 中的 UIAlertController 链式封装

WechatIMG207.jpeg
🌰🌰:
[UIAlertController alertControllerWithTitle:@"title" message:@"message" preferredStyle:UIAlertControllerStyleAlert]
.nn_addAction(@[@"取消", @"确定"], ^(UIAlertAction * _Nonnull action) {
NSLog(@"%@", action.title);
})
.nn_addTextField(@[@"请输入账号", @"请输入密码"], ^(UITextField * _Nonnull textField) {
NSLog(@"%@", textField.text);
})
.nn_present(true, ^{
});
必看:: 因为属性中包含handler 代码块(亲测简单的数字,字符串,数组等类型都支持自动补全),所以 XCode 不支持自动补全,需要配合 Code Snippets(代码块),将代码片段提取出来进行复用,具体详见这里。
#import
NS_ASSUME_NONNULL_BEGIN
@interface UIAlertController (Helper)
@property(nonatomic, strong, readonly) UIAlertController *(^nn_addAction)(NSArray *titles, void(^handler)(UIAlertAction *action));
@property(nonatomic, strong, readonly) UIAlertController *(^nn_addTextField)(NSArray *placeholders, void(^handler)(UITextField *textField));
@property(nonatomic, strong, readonly) UIAlertController *(^nn_present)(BOOL animated, void(^ __nullable completion)(void));
@end
NS_ASSUME_NONNULL_END
#import "UIAlertController+Helper.h"
- (UIAlertController * _Nonnull (^)(NSArray * _Nonnull, void (^ _Nonnull)(UIAlertAction * _Nonnull)))nn_addAction{
return ^(NSArray *titles, void(^handler)(UIAlertAction *action)){
[titles enumerateObjectsUsingBlock:^(NSString * _Nonnull title, NSUInteger idx, BOOL * _Nonnull stop) {
UIAlertActionStyle style = [title isEqualToString:@"取消"] ? UIAlertActionStyleCancel : UIAlertActionStyleDefault;
[self addAction:[UIAlertAction actionWithTitle:title style:style handler:handler]];
}];
return self;
};
}
- (UIAlertController * _Nonnull (^)(NSArray * _Nonnull, void (^ _Nonnull)(UITextField * _Nonnull)))nn_addTextField{
return ^(NSArray *placeholders, void(^handler)(UITextField *action)){
[placeholders enumerateObjectsUsingBlock:^(NSString * _Nonnull placeholder, NSUInteger idx, BOOL * _Nonnull stop) {
[self addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = placeholder;
if (handler) {
handler(textField);
}
}];
}];
return self;
};
}
@end
#import "UIViewController+Helper.h"
- (UIAlertController * _Nonnull (^)(BOOL, void (^ _Nullable)(void)))nn_present{
return ^(BOOL animated, void(^completion)(void)){
UIWindow *keyWindow = UIApplication.sharedApplication.delegate.window;
dispatch_async(dispatch_get_main_queue(), ^{
if (self.actions.count == 0) {
[keyWindow.rootViewController presentViewController:self animated:animated completion:^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDurationToast * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:animated completion:completion];
});
}];
} else {
[keyWindow.rootViewController presentViewController:self animated:animated completion:completion];
}
});
return self;
};
}
@end
例五: 富文本链式编程实现
NSAttributedString 富文本进阶(二):链式编程实现