为了账号安全,请及时绑定邮箱和手机立即绑定

MG--链式快速创建控件

标签:
iOS Swift

下载:
链接: https://pan.baidu.com/s/1_DLzF52rRaZMVPbFRzW5Jg 提取码: atht

  • 查看源码:

响应式编程

概念:响应式编程本质:众所周知,响应式编程基于观察者模式,即发布-订阅模式。

观察者模式是一种思想,即发布-订阅的思想,从中可以衍生出很多模型,本人见过的有发布者-订阅者模型、事件-事件源-监听器模型、被观察者-发射器-订阅者模型,就这三种模型而言,肯定都是属于响应式编程思想。只要是观察者模式,都是响应式编程。


作为一个iOS 开发者,那么你一定用过Masnory/ SnapKit;每个优秀的框架都有一套自己的编程思想,Masnory这里使用的是经典的链式编程思想。我们不妨来学习一波。
我们平时是这样用Masnory给UI写约束布局的

UIView *view  = [UIView new];
[self.view addSubview:view];
[view mas_makeConstraints:^(MASConstraintMaker *make) {
      make.top.left.equalTo(self.view);
      make.right.equalTo(self.view).offset(-20);
      make.bottom.equalTo(self.view).offset(-200);
}];

上述代码思想是通过.符号把多行代码链接成一句代码,增强了可读性,例如a.b(2).c(3)一系列操作,那么在OC中要实现b(参数)这种调用方式,那么必然就是Block了。没错,链式编程的方法调用返回的是Block,而且调用完Block之后必然会有返回值(该返回值就是操作对象本身),这样才能链式调用,而且Block的参数就是需要内部对象操作的值。

如何实现链式操作

  • 翻看Masonry源码


在.h的定义

在.m的实现


封装自己链式代码

通过查看Masonry源码,我们可以借鉴其优秀的思想,封装一下自己的代码,完成响应式编程创建UI控件。

平时我们自己创建一个UIButton的代码

UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn addTarget:self action:@selector(loginBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[btn setTitle:@"登录" forState:UIControlStateNormal];
btn.titleLabel.font = [UIFont systemFontOfSize:17];
[btn setBackgroundImage:[UIImage imageNamed:@"btn_bg_video_normal"] forState:UIControlStateNormal];>[btn setBackgroundImage:[UIImage imageNamed:@"btn_bg_video_pressed"] forState:UIControlStateHighlighted];
[btn setBackgroundImage:[[UIImage imageNamed:@"btn_switch_av"] mg_stretchableImage] forState:UIControlStateDisabled];
btn.layer.cornerRadius = 20.0;
btn.clipsToBounds = YES;
[self.view addSubview:btn];

UIButton *registBtn = [UIButton >buttonWithType:UIButtonTypeCustom];
[registBtn setTitle:@"注册" forState:UIControlStateNormal];
[registBtn setTitleColor:[UIColor colorWithHexString:@"#498ad9"] forState:UIControlStateNormal];
[registBtn addTarget:self action:@selector(registBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:registBtn];

再看一下封装后的代码,看起来会比较紧凑,逼格高了 一个档次

// 登录按钮
UIButton *loginBtn = [UIButton speedCreatButtonWith:^(UIButton *button) {
       button.mg_Config()
       .mg_CornerRadius(20.0)
       .mg_FontSize(17)
       .mg_NormalText(@"登录")
       .mg_NormalBackgroundImage([UIImage imageNamed:@"btn_bg_video_normal"])
       .mg_SelectedBackgroundImage([UIImage imageNamed:@"btn_bg_video_pressed"])
       .mg_DisabledBackgroundImage([[UIImage imageNamed:@"btn_switch_av"] mg_stretchableImage])
       .mg_Selector(self, @selector(loginBtnAction), UIControlEventTouchUpInside)
       .mg_AddTo(self.view);
}];
// 注册
UIButton *registBtn = [UIButton speedCreatButtonWith:^(UIButton *button) {
       button.mg_Config()
       .mg_NormalText(@"注册")
       .mg_NormalTextColor([UIColor colorWithHexString:@"#498ad9"])
       .mg_Selector(self, @selector(registBtnAction:), UIControlEventTouchUpInside)
       .mg_AddTo(self.view);
}];

有人担心这样的代码会造成循环引用?

  • 首先产生循环引用的原因:
    • block任何时候都会强引用在block代码块内部的对象,block消失,则强引用消失,block一直留存,强引用一直在,所以问题的关键是block是否会消失,如果A对象直接或者间接强引用一个block,block正好又强引用对象,那么就产生的循环引用。
  • 然后参考系统UIView封装动画的Block:
    • 首先循环引用发生的条件就是持有这个block的对象,被block里边加入的对象持有。当然是强引用。所以UIView的动画block不会造成循环引用的原因就是,这是个类方法,当前控制器不可能强引用一个类,所以循环无法形成。
      UIView中的block持有当前控制器,但是当前控制器中是没有持有UIView类的,没有形成循环.当动画结束时,UIView会结束持有这个block,如果没有别的对象持有block的话,block对象就会被释放掉,从而block会释放掉对self的持有,整个内存引用关系被解除.
  • 最后查看masonry源码:
    • masonry中设置布局的方法中的block对象并没有被View所引用,而是直接在方法内部同步执行,执行完以后block将释放,其中捕捉的外部变量的引用计数也将还原到之前。

本文参考Masonry的Block,是不存在循环引用的,可以放心大胆的使用self,不必担心循环引用造成内存泄漏.

总结通用情况 : 在block本身不被self持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用weakself了。




封装一个UILabel

只展示部分代码
.h实现

#import <UIKit/UIKit.h>

#pragma mark - UILabel
@interface UILabel (SpeedCreat)
/// 初始化
+ (UILabel *)label;

/// 初始化设置
@property (nonatomic,copy,readonly) UILabel *(^mg_Config)(void);
/// 是否可用
@property (nonatomic,assign,readonly) UILabel *(^mg_Enabled)(BOOL value);
/// 是否允许交互
@property (nonatomic,assign,readonly) UILabel *(^mg_UserInteractionEnabled)(BOOL value);
/// 是否隐藏
@property (nonatomic,assign,readonly) UILabel *(^mg_Hidden)(BOOL value);
/// frame
@property (nonatomic,assign,readonly) UILabel *(^mg_Frame)(CGRect value);
/// 文本
@property (nonatomic,copy,readonly) UILabel *(^mg_Text)(NSString *value)
@end

.m实现

#import "UIView+SpeedCreat.h"

@implementation UILabel (SpeedCreat)

+ (UILabel *)label {
    return [[UILabel alloc] init];
}

- (UILabel*(^)(void))mg_Config {
    return ^ () {
        self.text = @"label";
        [self sizeToFit];
        self.font = [UIFont systemFontOfSize:14];
        self.textColor = [UIColor blackColor];
        self.textAlignment = NSTextAlignmentLeft;
        self.numberOfLines = 1;
        self.backgroundColor = [UIColor clearColor];
        self.lineBreakMode = NSLineBreakByWordWrapping;
        self.shadowColor = [UIColor clearColor];
        self.shadowOffset = CGSizeMake(0, 0);
        return self;
    };
}

- (UILabel * _Nonnull (^)(BOOL))mg_Enabled {
    return ^(BOOL value) {
        self.enabled = value;
        return self;
    };
}

- (UILabel * _Nonnull (^)(BOOL))mg_UserInteractionEnabled {
    return ^(BOOL value) {
        self.userInteractionEnabled = value;
        return self;
    };
}

- (UILabel * _Nonnull (^)(CGFloat))mg_Alpha {
    return ^(CGFloat value) {
        self.alpha = value;
        return self;
    };
}

- (UILabel * _Nonnull (^)(BOOL))mg_Hidden {
    return ^(BOOL value) {
        self.hidden = value;
        return self;
    };
}

/// frame
- (UILabel*(^)(CGRect value))mg_Frame {
    return ^ (CGRect value) {
        self.frame = value;
        return self;
    };
}

/// 文字
- (UILabel*(^)(NSString *value))mg_Text {
    return ^ (NSString *value) {
        self.text = value;
        return self;
    };
}

@end

怎么使用:

导入头文件 #import "UIView+SpeedCreat.h"就可以愉快的玩耍啦

UILabel *titleLabel  = [UILabel speedCreatLabelWith:^(UILabel *lb) {
        lb.mg_TextAlignment(NSTextAlignmentCenter)
        .mg_Text(titleText)
        .mg_Font([UIFont fontWithName:@"PingFangSC-Regular" size:22])
        .mg_TextColor(HEX_ARGB(@"000000"))
        .mg_AddTo(self.contentView);
}];

提取码: atht


github

项目 简介
MGDS_Swif 逗视视频直播
MGMiaoBo 喵播视频直播
MGDYZB 斗鱼视频直播
MGDemo n多小功能合集
MGBaisi 高度仿写百思
MGSinaWeibo 高度仿写Sina
MGLoveFreshBeen 一款电商App
MGWeChat 小部分实现微信功能
MGTrasitionPractice 自定义转场练习
DBFMDemo 豆瓣电台
MGPlayer 一个播放视频的Demo
MGCollectionView 环形图片排布以及花瓣形排布
MGPuBuLiuDemo 瀑布流–商品展
MGSlideViewDemo 一个简单点的侧滑效果,仿QQ侧滑
MyResume 一个展示自己个人简历的Demo
GoodBookDemo 好书

逗视介绍1.gif
逗视介绍2.gif



点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消