iOS 链式编程实战, 更优雅的代码编写方式

时间:2021-7-21 作者:qvyue

链式编程最难得地方是想通,实现是如此的简单:

例一: 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 
例二:圆角阴影
iOS 链式编程实战, 更优雅的代码编写方式
链式圆角阴影效果图.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 链式封装
iOS 链式编程实战, 更优雅的代码编写方式
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 富文本进阶(二):链式编程实现

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。