这篇文章就是针对,对MLChainContainer文件解锁

2019-09-17 13:07栏目:大奖888官网登录
TAG:

图片 1

传送门:链式编制程序小德姆o

在podFile中加多 pod 'MLChain',并安装达成后打开。创立自身的Pod并表露详细步骤

这个是PYKit的段代码,点击这里查看全数

那篇小说是 Masonry 框架源码的剖判和笔记。学习Masonry此前,先领悟这几个框架设计的初志---古板的使用系统API进行纯代码布局的欠缺。然后,依据Masonry常见的多少个链式语法中,顺藤摘瓜地了然Masonry的调用栈。末了,学习并思量这一个框架用到的设计形式链式编制程序思想。

由于链式方法供给基于项目中的类已落到实处的章程生成方法列表,作者将链式方法放在固定路线,并把持有的链式方法都坐落MLChainContainer.h和MLChainContainer.m文件中。

ios 开垦对于圆角的裁切,纠纷异常的大,于是做了一个对照,相比进度上边会有详尽的分解,得出结论为相同运行环境下,用shapLayer 裁切与用maskToBounds裁切耗时比例大概为 **6 : 7**

  • 系统给的电动布局(AutoLayout)的API

图片 2须解锁文件图示图片 3对MLChainContainer文件解锁

其后您恐怕这么切圆角

在品种的info.plist文件中,设置项目地址用于链式方法的写入(第四步操作的首要依附)key:ProjectDirectoryvalue:$

BaseFilletShadowView *view = [BaseFilletShadowView new]; view .config .setUpCutRect(CGRectMake(0, 0, -1, -1))//裁切的位置及范围 优先级低于 cutRectEdgeWithSelf .setUpCutRectEdgeWithSelf(UIEdgeInsetsMake(20, 20, 20, 20))//裁切的位置及范围 .setUpRadius//四个角切圆的圆形的半径 .setUpLeftTopAddRadius//左上角追加圆角半径 .setUpLeftBottomAddRadius//左下角追加圆角半径 .setUpRightTopAddRadius//右上角追加圆角半径 .setUpRightBottomAddRadius;//右下角追加圆角半径 
+(instancetype)constraintWithItem:view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:multiplier constant:c;

图片 4plist文件增添键值对

  1. 布局:内部加多了二个承受阴影的shadowLayer 与一个担当圆形切图的containerView,况且按照config天性统一或个别设置各种角的弧度。
  2. 调用:config加多了链式调用方法。view 链式调用在这边
  • 价值观代码中央银行使系统API进行布局

导入MLChain的头文件,然后调用生成方法,运维一遍,你要的链式方法都在MLChainContainer.h和MLChainContainer.m文件中因为链式方法数量大且出错开上下班时间麻烦修复,作者在变化时做了备份。小编在运维时会在计算机桌面也生成一份,并将旧的一份丢到回收站。若是cocoaPods必要更新,则需求将复制内容到MLChainContainer.h和MLChainContainer.m文件。

config .h

图片 5调用生成方法

#import <UIKit/UIKit.h>@interface BaseFilletShadowViewConfig : NSObject/**裁切的位置及范围*/@property (nonatomic,assign) CGRect cutRect;- (BaseFilletShadowViewConfig *(CGRect cutRect)) setUpCutRect;/**圆形的半径*/@property (nonatomic,assign) CGFloat radius;- (BaseFilletShadowViewConfig *(CGFloat radius)) setUpRadius;/**四个角的半径控制接口*/@property (nonatomic,assign) CGFloat leftTopAddRadius;- (BaseFilletShadowViewConfig *(CGFloat leftTopAddRadius)) setUpLeftTopAddRadius;@property (nonatomic,assign) CGFloat leftBottomAddRadius;- (BaseFilletShadowViewConfig *(CGFloat leftBottomAddRadius)) setUpLeftBottomAddRadius;@property (nonatomic,assign) CGFloat rightTopAddRadius;- (BaseFilletShadowViewConfig *(CGFloat rightTopAddRadius)) setUpRightTopAddRadius;@property (nonatomic,assign) CGFloat rightBottomAddRadius;- (BaseFilletShadowViewConfig *(CGFloat rightBottomAddRadius)) setUpRightBottonAddRadius;///**图片的透明度*///@property (nonatomic,assign) CGFloat alpha;//- (BaseFilletShadowViewConfig *(CGFloat alpha)) setUpAlpha;@end
- viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.view.backgroundColor = [UIColor yellowColor]; UIView *subView = [[UIView alloc] init]; subView.backgroundColor = [UIColor redColor]; // 在设置约束前,先将子视图添加进来 [self.view addSubview:subView]; // 使用autoLayout约束,禁止将AutoresizingMask转换为约束 [subView setTranslatesAutoresizingMaskIntoConstraints:NO]; // 设置subView相对于VIEW的上左下右各40像素 NSLayoutConstraint *constraintTop = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:40]; NSLayoutConstraint *constraintLeft = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:40]; // 由于iOS坐标系的原点在左上角,所以设置下,右边距使用负值 NSLayoutConstraint *constraintBottom = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-40]; NSLayoutConstraint *constraintRight = [NSLayoutConstraint constraintWithItem:subView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-40]; // 将四条约束加进数组中 NSArray *array = [NSArray arrayWithObjects:constraintTop, constraintLeft, constraintBottom, constraintRight, nil]; // 把约束条件设置到父视图的Contraints中 [self.view addConstraints:array];}

链式方法生成一遍就能够使用,下次利用除非有新措施创新。

config .m

看得出,系统观念的代码布局有一些麻烦。为了简化上述守旧布局代码,被广泛应用的第三方框架 Masonry 对AutoLayout 进行了打包,斯维夫特版则是 SnapKit。那篇作品便是针对 Masonry 源代码的剖析与上学笔记。在这前边,如下图所示,是 Masonry 源代码的结构图:

图片 6千帆竞发运用

#import "BaseFilletShadowViewConfig.h"@implementation BaseFilletShadowViewConfig- (BaseFilletShadowViewConfig *(CGRect cutRect)) setUpCutRect { return ^(CGRect cutRect) { self.cutRect = cutRect; return self; };}- (BaseFilletShadowViewConfig *(CGFloat radius)) setUpRadius { return ^(CGFloat radius) { self.radius = radius; return self; };}- (BaseFilletShadowViewConfig *(CGFloat leftTopRadius)) setUpLeftTopAddRadius { return ^(CGFloat radius) { self.leftTopAddRadius = radius; return self; };}- (BaseFilletShadowViewConfig *(CGFloat leftBottomRadius)) setUpLeftBottomAddRadius { return ^(CGFloat radius) { self.leftBottomAddRadius = radius; return self; };}- (BaseFilletShadowViewConfig *(CGFloat rightTopRadius)) setUpRightTopAddRadius { return ^(CGFloat radius) { self.rightTopAddRadius = radius; return self; };}- (BaseFilletShadowViewConfig *(CGFloat rightBottomRadius)) setUpRightBottonAddRadius { return ^(CGFloat radius) { self.rightBottomAddRadius = radius; return self; };}- (BaseFilletShadowViewConfig *(CGFloat alpha)) setUpAlpha { return ^(CGFloat alpha) { self.alpha = alpha; return self; };}@end

图片 7Masonry 源码结构图

 UIView *view = UIView.mlc_make.frame_(100, 100, 100, 100).backgroundColor([UIColor cyanColor]).chainObject; [self.view addSubview:view];

BaseFilletShadowView.h

2.1 mas_makeConstraints:外界调用

  • 调用例子
#import "Masonry.h"

[self.containerView addSubview:self.bannerView];[self.bannerView mas_makeConstraints:^(MASConstraintMaker *make) { make.leading.equalTo(self.containerView.mas_leading); make.top.equalTo(self.containerView.mas_top); make.trailing.equalTo(self.containerView.mas_trailing); make.height.equalTo(@(kViewWidth;}];

图片 8运营效果MLChain详细使用此处应该demo

#import <UIKit/UIKit.h>#import "BaseFilletShadowViewConfig.h"/// 圆角阴影view@interface BaseFilletShadowView : UIView@property (nonatomic,strong) BaseFilletShadowViewConfig *config;/** 设置阴影必须要设置这个layer 要保证这个layer 在最底层 */@property (nonatomic,strong) CALayer *shadowLayer;/** 在这个上边布局, */@property (nonatomic,strong) UIView *containerView;/** 开始切图 */-  reCut;/** 取消切图 */-  unCunt;@end

2.2 mas_makeConstraints:实现原理,通过导入的头文件解析

  • Masonry.h
#import <Foundation/Foundation.h>//! Project version number for Masonry.FOUNDATION_EXPORT double MasonryVersionNumber;//! Project version string for Masonry.FOUNDATION_EXPORT const unsigned char MasonryVersionString[];#import "MASUtilities.h"#import "View+MASAdditions.h"#import "View+MASShorthandAdditions.h"#import "ViewController+MASAdditions.h"#import "NSArray+MASAdditions.h"#import "NSArray+MASShorthandAdditions.h"#import "MASConstraint.h"#import "MASCompositeConstraint.h"#import "MASViewAttribute.h"#import "MASViewConstraint.h"#import "MASConstraintMaker.h"#import "MASLayoutConstraint.h"#import "NSLayoutConstraint+MASDebugAdditions.h"

其中View+MASAdditions分类为UIView添加了mas_makeConstraints方法

  • View+MASAdditions.m
- (NSArray *)mas_makeConstraints:(MASConstraintMaker *))block { self.translatesAutoresizingMaskIntoConstraints = NO; MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self]; block(constraintMaker); return [constraintMaker install];}
  • MASConstraintMaker.m
@interface MASConstraintMaker () <MASConstraintDelegate>@property (nonatomic, weak) MAS_VIEW *view;@property (nonatomic, strong) NSMutableArray *constraints;@end

- initWithView:(MAS_VIEW *)view { self = [super init]; if  return nil; self.view = view; self.constraints = NSMutableArray.new; return self;}

BaseFilletShadowView.m

2.3 .top:通过MASConstraintMaker类源码分析

先解析设置 首先个约束属性 的情况:例如

make.top.equalTo(self.containerView.mas_top);
#import "BaseFilletShadowView.h"#import <Masonry/Masonry.h>@interface BaseFilletShadowView ()@property (nonatomic,strong) CAShapeLayer *shapeLayer;@property (nonatomic,assign) BOOL isCut;@property (nonatomic,assign) CGRect lastDrawFrame;@end@implementation BaseFilletShadowView#pragma mark - init- (instancetype)initWithFrame:frame { if (self = [super initWithFrame:frame]) { [self.layer addSublayer:self.shadowLayer]; [self addSubview:self.containerView]; [self.containerView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo; }]; } return self;}#pragma mark - functions-  unCunt { self.containerView.layer.mask = nil;}-  reCut { self.isCut = true; if (self.config.radius <= 0 && self.config.leftTopAddRadius <= 0 && self.config.leftBottomAddRadius <= 0 && self.config.rightTopAddRadius <= 0 && self.config.rightBottomAddRadius <= 0) { return; } self.containerView.layer.mask = self.shapeLayer; [self setupShapeLayerIfNeede];}-  setupShapeLayerIfNeede { if (CGSizeEqualToSize(self.frame.size, self.lastDrawFrame.size)) { return; } self.lastDrawFrame = self.frame; __weak typeofweakSelf = self; [self createPathWithRect:self.config.cutRect andCallBack:^(CGMutablePathRef path) { weakSelf.shapeLayer.path = path; weakSelf.shadowLayer.shadowPath = path; }]; [self setupShadowLayer];}-  setupShadowLayer { self.shadowLayer.backgroundColor = self.backgroundColor.CGColor; self.shadowLayer.frame = self.bounds;}//MARK: - 创建切圆路径-  createPathWithRect:rect andCallBack: (CGMutablePathRef path))block { if  return; CGMutablePathRef path = [self createMutablePathRefWithRect:rect]; block; CFRelease;}- (CGMutablePathRef)createMutablePathRefWithRect:rect { CGRect cutRect = rect; CGFloat minx = CGRectGetMinX,//矩形中最小的x midx = CGRectGetMidX,//矩形中最大x值的一半 maxx = CGRectGetMaxX;//矩形中最大的x值 CGFloat miny = CGRectGetMinY,//矩形中最小的Y值 midy = CGRectGetMidY,//矩形中最大Y值的一半 maxy = CGRectGetMaxY;//矩形中最大的Y值 CGFloat radius = self.config.radius; CGFloat leftTopRadiu = radius + self.config.leftTopAddRadius, rightTopRadiu = radius + self.config.rightTopAddRadius, leftBottomRadiu = radius + self.config.leftBottomAddRadius, rightBottomRadiu = radius + self.config.rightBottomAddRadius; CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, nil, minx, midy); CGPathAddArcToPoint(path, nil, minx, miny, midx, miny, leftTopRadiu); CGPathAddArcToPoint(path, nil, maxx, miny, maxx, midy, rightTopRadiu); CGPathAddArcToPoint(path, nil, maxx, maxy, midx, maxy, rightBottomRadiu); CGPathAddArcToPoint(path, nil, minx, maxy, minx, midy, leftBottomRadiu); return path;}// MARK: properties get && set- (BaseFilletShadowViewConfig *)config { if  { _config = [BaseFilletShadowViewConfig new]; _config .setUpCutRect(self.bounds) .setUpRadius .setUpAlpha; } return _config;}- (CAShapeLayer *)shapeLayer { if(!_shapeLayer) { _shapeLayer = [CAShapeLayer new]; } return _shapeLayer;}- containerView { if (!_containerView) { _containerView = [UIView new]; } return _containerView;}- (CALayer *)shadowLayer { if (!_shadowLayer) { _shadowLayer = [CALayer new]; } return _shadowLayer;}- layoutSubviews { [super layoutSubviews]; self.shapeLayer.frame = self.bounds; self.shadowLayer.frame = self.bounds;}@end
2.3.1 MASConstraintMaker的分析
  • MASConstraintMaker.m
- (MASConstraint *)top { return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];}- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];}- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute]; MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute]; if ([constraint isKindOfClass:MASViewConstraint.class]) { //replace with composite constraint NSArray *children = @[constraint, newConstraint]; MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self; [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } if (!constraint) { newConstraint.delegate = self; [self.constraints addObject:newConstraint]; } return newConstraint;}

该措施重临的newConstraint是一个MASViewConstraint类的示范,而MASViewConstraint类又是MASConstraint的子类,重临类型写成MASConstraint没毛病。

代码相当多,近来能够只先看if (!constraint)个中的代码。可见,最终设置 newConstraint对象代理为self (即 MASConstraintMaker),并增加到一早先筹算好的 self.constraints 数组中,重返。

其中,设置 MASViewConstraintnewConstraint 对象的 MASConstraintDelegate 代理为self (即 MASConstraintMaker),其职能正是为了能够同临时间安装多个约束属性!即链式语法。

  • MASConstraint+Private.h
@protocol MASConstraintDelegate <NSObject>/** * Notifies the delegate when the constraint needs to be replaced with another constraint. For example * A MASViewConstraint may turn into a MASCompositeConstraint when an array is passed to one of the equality blocks */- constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint;- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;@end
  1. 图片 9
2.3.2 MASConstraintMaker的接二连三分析

第2.3.1节的MASConstraintMaker.m代码中,先是初阶化了 MASViewAttribute 对象并保存了 view、item以及 NSLayoutAttribute 两本天性。

  • MASViewAttribute.m
- initWithView:(MAS_VIEW *)view layoutAttribute:(NSLayoutAttribute)layoutAttribute { self = [self initWithView:view item:view layoutAttribute:layoutAttribute]; return self;}- initWithView:(MAS_VIEW *)view item:item layoutAttribute:(NSLayoutAttribute)layoutAttribute { self = [super init]; if  return nil; _view = view; _item = item; _layoutAttribute = layoutAttribute; return self;}

接下来又伊始化了 MASViewConstraint 对象,内部布署了些暗许参数并保留了上述的率先个约束参数 MASViewAttribute

  • MASViewConstraint.m
- initWithFirstViewAttribute:(MASViewAttribute *)firstViewAttribute { self = [super init]; if  return nil; _firstViewAttribute = firstViewAttribute; self.layoutPriority = MASLayoutPriorityRequired; self.layoutMultiplier = 1; return self;}

图片 10

2.4 .equalTo :通过基类MASConstraint会同子类MASViewConstraint分析

先是个约束属性 设置完后,走到.equalTo时,前边重回已经是一个 MASViewConstraint(继承自MASConstraint) 对象了,由此调用的是在基类MASConstraint中声称并促成的block属性getter方法。

  • MASConstraint.m
- (MASConstraint * equalTo { return ^id(id attribute) { return self.equalToWithRelation(attribute, NSLayoutRelationEqual); };}

其中,基类 MASConstraint 仅仅申明,并未有达成equalToWithRelation空泛方法。可是,如2.3节中的链式语法.top,该格局再次回到的newConstraint实际上是其子类--MASViewConstraint类的实例,故而可调用子类MASViewConstraint实现的equalToWithRelation方法:

  • MASViewConstraint.m
- (MASConstraint * (id, NSLayoutRelation))equalToWithRelation { return ^id(id attribute, NSLayoutRelation relation) { if ([attribute isKindOfClass:NSArray.class]) { NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation"); NSMutableArray *children = NSMutableArray.new; for (id attr in attribute) { MASViewConstraint *viewConstraint = [self copy]; viewConstraint.layoutRelation = relation; viewConstraint.secondViewAttribute = attr; [children addObject:viewConstraint]; } MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self.delegate; [self.delegate constraint:self shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } else { NSAssert(!self.hasLayoutRelation || self.layoutRelation == relation && [attribute isKindOfClass:NSValue.class], @"Redefinition of constraint relation"); self.layoutRelation = relation; self.secondViewAttribute = attribute; return self; } };}

代码很多,一时半刻可先看else {在这之中的代码。

上述是用 instrumentstime profiler 来 对运转时刻做的总计过程。

self.layoutRelation = relation;

首先是 self.layoutRelation 保存了约束关系且重写了 set 方法,在中间用 self.hasLayoutRelation 这个 BOOL 标志已经有约束关系。

  • MASViewConstraint.m
- setLayoutRelation:(NSLayoutRelation)layoutRelation { _layoutRelation = layoutRelation; self.hasLayoutRelation = YES;}
  1. 自定义五个tableView : PYMaskToBoundsTableViewPYRoundViewTableView
  2. 让两个tableView,除去 cellview 的裁切格局各异 外其余都一致。
  3. 滚动其中一个,别的二个tableView 供给联合浮动。
  4. 观察tableViewcellForRow措施,对比耗时。
self.secondViewAttribute = attribute;

然后同样是重写了 self.secondViewAttributeset 方法,这里会基于不一样的事态做差别的操作。

- setSecondViewAttribute:secondViewAttribute { if ([secondViewAttribute isKindOfClass:NSValue.class]) { [self setLayoutConstantWithValue:secondViewAttribute]; } else if ([secondViewAttribute isKindOfClass:MAS_VIEW.class]) { _secondViewAttribute = [[MASViewAttribute alloc] initWithView:secondViewAttribute layoutAttribute:self.firstViewAttribute.layoutAttribute]; } else if ([secondViewAttribute isKindOfClass:MASViewAttribute.class]) { MASViewAttribute *attr = secondViewAttribute; if (attr.layoutAttribute == NSLayoutAttributeNotAnAttribute) { _secondViewAttribute = [[MASViewAttribute alloc] initWithView:attr.view item:attr.item layoutAttribute:self.firstViewAttribute.layoutAttribute];; } else { _secondViewAttribute = secondViewAttribute; } } else { NSAssert(NO, @"attempting to add unsupported attribute: %@", secondViewAttribute); }}

当中,第1种情景相应的是:

make.height.equalTo

传入 NSValue 的时, 会直接设置 constraintoffset, centerOffset, sizeOffset, 或者 insets。调用栈如下:

//MASViewConstraint.mif ([secondViewAttribute isKindOfClass:NSValue.class]) { [self setLayoutConstantWithValue:secondViewAttribute];}//MASConstraint.m- setLayoutConstantWithValue:(NSValue *)value { if ([value isKindOfClass:NSNumber.class]) { self.offset = [(NSNumber *)value doubleValue]; } else if (strcmp(value.objCType, @encode == 0) { CGPoint point; [value getValue:&point]; self.centerOffset = point; } else if (strcmp(value.objCType, @encode == 0) { CGSize size; [value getValue:&size]; self.sizeOffset = size; } else if (strcmp(value.objCType, @encode(MASEdgeInsets)) == 0) { MASEdgeInsets insets; [value getValue:&insets]; self.insets = insets; } else { NSAssert(NO, @"attempting to set layout constant with unsupported value: %@", value); }}//MASViewConstraint.m- setOffset:offset { self.layoutConstant = offset;}//MASViewConstraint.m- setLayoutConstant:layoutConstant { _layoutConstant = layoutConstant;#if TARGET_OS_MAC && !(TARGET_OS_IPHONE || TARGET_OS_TV) if (self.useAnimator) { [self.layoutConstraint.animator setConstant:layoutConstant]; } else { self.layoutConstraint.constant = layoutConstant; }#else self.layoutConstraint.constant = layoutConstant;#endif}

第2种情形,一般是一向传入一个视图:

make.top.equalTo

此时, 就能够初步化八个 layoutAttribute 属性与 firstViewArribute 相同的 MASViewAttribute, 下面的代码就可以使视图与 view 顶上部分对齐。

第3种状态,会流传三个视图的 MASViewAttribute:

make.top.equalTo(view.mas_bottom);

使用这种写法时, 一般是因为约束的偏向分化. 那行代码会使视图的最上端与 view 的最底层对齐。

2.5 .height.width:梅森ry的链式语法性子

  • 调用例子
make.height.width.equalTo;

其中,.height 设置先是个约束属性时,调用的是 MASConstraintMaker.m 中的 .heightaddConstraintWithLayoutAttribute,以及- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute

  • MASConstraintMaker.m
- (MASConstraint *)height { return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];}- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];}- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute]; MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute]; if ([constraint isKindOfClass:MASViewConstraint.class]) { //replace with composite constraint NSArray *children = @[constraint, newConstraint]; MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self; [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } if (!constraint) { newConstraint.delegate = self; [self.constraints addObject:newConstraint]; } return newConstraint;}

该格局调用栈重临的是叁个MASViewConstraint(父类是 MASConstraint) 对象。

因此,通过 .width 设置其次个约束属性的时候,调用的率先基类 MASConstraint.m 中的.width,然后调用由子类MASViewConstraint实现的addConstraintWithLayoutAttribute方式。那时候的调用栈为:

  • MASConstraint.m
- (MASConstraint *)width { return [self addConstraintWithLayoutAttribute:NSLayoutAttributeWidth];}- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute __unused)layoutAttribute { MASMethodNotImplemented();}
  • MASViewConstraint.m
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { NSAssert(!self.hasLayoutRelation, @"Attributes should be chained before defining the constraint relation"); return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];}

这其中,self.delegate 是怎么吧?如2.3.1节所述,MASConstraintMaker.m 中设置了 MASViewConstraintnewConstraint 对象的 MASConstraintDelegate 代理为“self” (即 MASConstraintMaker),其功用便是为了可以同期安装八个约束属性,即链式语法。所以,第二个设置约束属性跟第叁个设置约束属性最终 调用的方式一致(都以MASConstraintMaker.m中落到实处的addConstraintWithLayoutAttribute)。

  • MASConstraintMaker.m
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute]; MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute]; if ([constraint isKindOfClass:MASViewConstraint.class]) { //replace with composite constraint NSArray *children = @[constraint, newConstraint]; MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self; [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } if (!constraint) { newConstraint.delegate = self; [self.constraints addObject:newConstraint]; } return newConstraint;}

当设置 第叁遍约束属性 并实行完今后,我们还足以窥见 constraint 不为 nil,而是多少个 MASViewConstraint 对象 ,所以该艺术调用栈再次回到的不是 MASViewConstraint 对象,而是 MASCompositeConstraint 这几个目的了,上面大家来看看那么些类。

2.6 约束的汇集: MASCompositeConstraint

MASCompositeConstraint 是约束的群集,它在那之中有个个人的数组用来贮存三个 MASViewAttribute 对象。

make.height.width.equalTo

当设置 第三个约束属性,走到 .width 时,最后走的是:

  • MASConstraintMaker.m
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute]; MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute]; if ([constraint isKindOfClass:MASViewConstraint.class]) { //replace with composite constraint NSArray *children = @[constraint, newConstraint]; MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self; [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } ....}

内部,能够成功的走进 if判读里面,将 .height .wight 两契约束 MASViewConstraint对象塞到数组里,创立 MASCompositeConstraint 对象,並且一样设置了 delegate,最终还把 self.constraints 里面事先增加好的牢笼 MASViewConstraint 对象替换到了 MASCompositeConstraint 对象。

#pragma mark - MASConstraintDelegate- constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint { NSUInteger index = [self.childConstraints indexOfObject:constraint]; NSAssert(index != NSNotFound, @"Could not find constraint %@", constraint); [self.childConstraints replaceObjectAtIndex:index withObject:replacementConstraint];}

另外,大家能够点击 MASCompositeConstraint 起初化方法里探望,它里面会经过 for 循环,把数组里面包车型大巴兼具 MASViewConstraint 对象同样设置了 delegate

- initWithChildren:(NSArray *)children { self = [super init]; if  return nil; _childConstraints = [children mutableCopy]; for (MASConstraint *constraint in _childConstraints) { constraint.delegate = self; } return self;}

如此那般做的目标并且是为着能够继续链式调用,譬喻大家再设置其四个约束属性 .left

make.height.width.left.equalTo;

此刻的调用栈如下:

  • MASConstraint.m
- (MASConstraint *)left { return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];}
  • MASCompositeConstraint.m
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { [self constraint:self addConstraintWithLayoutAttribute:layoutAttribute]; return self;}- (MASConstraint *)constraint:(MASConstraint __unused *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { id<MASConstraintDelegate> strongDelegate = self.delegate; MASConstraint *newConstraint = [strongDelegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute]; newConstraint.delegate = self; [self.childConstraints addObject:newConstraint]; return newConstraint;}

可以窥见,这里又是因此 delegate 方式,调用 MASConstraintMaker 工厂类中的:

  • MASConstraintMaker.m
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute { MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute]; MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute]; if ([constraint isKindOfClass:MASViewConstraint.class]) { //replace with composite constraint NSArray *children = @[constraint, newConstraint]; MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self; [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } if (!constraint) { newConstraint.delegate = self; [self.constraints addObject:newConstraint]; } return newConstraint;}

此刻,注意到七个 if 体都未有走进去,既不像第贰遍,也不像第贰回约束设置的时候。所以,这一次只有是开首化了个 MASViewConstraint 对象就一贯再次来到了,然后回到上个方法中增加到 MASCompositeConstraint 的私有数组 self.childConstraints 中回到备用。

图片 11三处的同名方法最终调用的恐怕MASConstraintMaker中的方法

关于三次 约束设置之后的 .equalTo,因为实行完 .left 时,重临的是 MASCompositeConstraint 对象,到这一步的时候会有一些变化,调用栈如下:

  • MASConstraint.m
- (MASConstraint * equalTo { return ^id(id attribute) { return self.equalToWithRelation(attribute, NSLayoutRelationEqual); };}
  • MASCompositeConstraint.m
- (MASConstraint * (id, NSLayoutRelation))equalToWithRelation { return ^id(id attr, NSLayoutRelation relation) { for (MASConstraint *constraint in self.childConstraints.copy) { constraint.equalToWithRelation(attr, relation); } return self; };}

能够窥见,这里会循环此前筹算好的私有数组 self.childConstraints,调用 MASViewConstraint.m 的 equalToWithRelation 方法,和方面讲的同样了。

2.7 增加约束到视图

mas_makeConstraints 方法的最终会调用 [constraintMaker install] 方法来增进全体存款和储蓄在 self.constraints 数组中的全体约束。

  • MASConstraintMaker.m
 - (NSArray *)install { if (self.removeExisting) { NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view]; for (MASConstraint *constraint in installedConstraints) { [constraint uninstall]; } } NSArray *constraints = self.constraints.copy; for (MASConstraint *constraint in constraints) { constraint.updateExisting = self.updateExisting; [constraint install]; } [self.constraints removeAllObjects]; return constraints;}

. 固然必要再行营造约束,也便是 调用 mas_remakeConstraints:办法,会先抽出视图的全部约束,然后通过二个 for 循环,调用 uninstall 来清空全数约束:

. 假设无需再度营造约束,会抽出 self.constraints 数组中盘算好的牢笼,通过 for 循环,调用 install 来把约束增添到视图上。

关于 install ,是基类 MASConstraint 的架空方法,方法体由MASViewConstraintMASCompositeConstraint 实现。而 MASCompositeConstraintinstall方法体中实际也是调用的由MASViewConstraint类完毕的install

  • MASConstraint.m
- install { MASMethodNotImplemented(); }
  • MASCompositeConstraint.m
- install { for (MASConstraint *constraint in self.childConstraints) { constraint.updateExisting = self.updateExisting; [constraint install]; }}
  • MASViewConstraint.m

那边代码相当多,就不分手解析了,直接分为7步写到源码的讲解中,如下所示:

- install { //如果约束以及存在并是 active 会直接返回。 if (self.hasBeenInstalled) { return; } //如果 self.layoutConstraint 响应了 isActive 方法并且不为空,会激活这条约束并添加到 mas_installedConstraints 数组中,最后返回。 if ([self supportsActiveProperty] && self.layoutConstraint) { self.layoutConstraint.active = YES; [self.firstViewAttribute.view.mas_installedConstraints addObject:self]; return; } //这边是获取即将用于初始化 NSLayoutConstraint 的子类 MASLayoutConstraint 的几个属性。 MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item; NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute; MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item; NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute; // alignment attributes must have a secondViewAttribute // therefore we assume that is refering to superview // eg make.left.equalTo //这边是判断当前即将添加的约束是否是 size 类型的并且 self.secondViewAttribute 也就是约束的第二个参数是 nil,(eg make.left.equalTo会自动将约束添加到约束的第一个参数视图的 superview 上。 if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) { secondLayoutItem = self.firstViewAttribute.view.superview; secondLayoutAttribute = firstLayoutAttribute; } //然后就会初始化 NSLayoutConstraint 的子类 MASLayoutConstraint。 MASLayoutConstraint *layoutConstraint = [MASLayoutConstraint constraintWithItem:firstLayoutItem attribute:firstLayoutAttribute relatedBy:self.layoutRelation toItem:secondLayoutItem attribute:secondLayoutAttribute multiplier:self.layoutMultiplier constant:self.layoutConstant]; layoutConstraint.priority = self.layoutPriority; layoutConstraint.mas_key = self.mas_key; //这段代码会先判断是否有约束第二个参数的视图,有的话会寻找约束第一个和第二参数视图的公共 Superview,相当于求两个数的最小公倍数;如果不满足第一个条件,会判断约束第一个参数是否是 size 类型的,是的话直接取到它的视图;最后都不满足会直接取到约束第一个参数视图父视图。 if (self.secondViewAttribute.view) { MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view]; NSAssert(closestCommonSuperview, @"couldn't find a common superview for %@ and %@", self.firstViewAttribute.view, self.secondViewAttribute.view); self.installedView = closestCommonSuperview; } else if (self.firstViewAttribute.isSizeAttribute) { self.installedView = self.firstViewAttribute.view; } else { self.installedView = self.firstViewAttribute.view.superview; } //如果需要升级当前的约束就会获取原有的约束,并替换为新的约束,这样就不需要再次为 view 安装约束。如果原来的 view 中不存在可以升级的约束,那么就会在上一步寻找到的 installedView 上面添加约束。 MASLayoutConstraint *existingConstraint = nil; if (self.updateExisting) { existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint]; } if (existingConstraint) { // just update the constant existingConstraint.constant = layoutConstraint.constant; self.layoutConstraint = existingConstraint; } else { [self.installedView addConstraint:layoutConstraint]; self.layoutConstraint = layoutConstraint; [firstLayoutItem.mas_installedConstraints addObject:self]; }}

内部第步中的mas_closestCommonSuperview主意,它会搜索 firstLayoutItem 和 secondLayoutItem 七个视图的公物 superview, 约等于求多个数的矮小公倍数.

  • View+MASAdditions.m
- (instancetype)mas_closestCommonSuperview:(MAS_VIEW *)view { MAS_VIEW *closestCommonSuperview = nil; MAS_VIEW *secondViewSuperview = view; while (!closestCommonSuperview && secondViewSuperview) { MAS_VIEW *firstViewSuperview = self; while (!closestCommonSuperview && firstViewSuperview) { if (secondViewSuperview == firstViewSuperview) { closestCommonSuperview = secondViewSuperview; } firstViewSuperview = firstViewSuperview.superview; } secondViewSuperview = secondViewSuperview.superview; } return closestCommonSuperview;}

3.1 make.edges.equalTo

  • 例子
make.edges.equalTo

我们再来看看这种写法,调用栈如下:

  • MASConstraintMaker.m
- (MASConstraint *)edges { return [self addConstraintWithAttributes:MASAttributeTop | MASAttributeLeft | MASAttributeRight | MASAttributeBottom];}- (MASConstraint *)addConstraintWithAttributes:(MASAttribute)attrs { __unused MASAttribute anyAttribute = (MASAttributeLeft | MASAttributeRight | MASAttributeTop | MASAttributeBottom | MASAttributeLeading | MASAttributeTrailing | MASAttributeWidth | MASAttributeHeight | MASAttributeCenterX | MASAttributeCenterY | ...... NSMutableArray *attributes = [NSMutableArray array]; if (attrs & MASAttributeLeft) [attributes addObject:self.view.mas_left]; if (attrs & MASAttributeRight) [attributes addObject:self.view.mas_right]; if (attrs & MASAttributeTop) [attributes addObject:self.view.mas_top]; ...... NSMutableArray *children = [NSMutableArray arrayWithCapacity:attributes.count]; for (MASViewAttribute *a in attributes) { [children addObject:[[MASViewConstraint alloc] initWithFirstViewAttribute:a]]; } MASCompositeConstraint *constraint = [[MASCompositeConstraint alloc] initWithChildren:children]; constraint.delegate = self; [self.constraints addObject:constraint]; return constraint;}

代码太多轻松了一部分,能够发掘这段代码成效正是回到一个含有多契约束的 MASCompositeConstraint 对象,接着前面包车型客车操作也没什么不相同的了。

3.2 make.edges.equalTo(UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f));

地点3.第11中学例子的写法还足以改成那样:

make.edges.equalTo(UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f));

这里的 equalTo 供给注意下,它是二个宏,定义在 MASConstraint.h 中:

  • MASConstraint.h
#define mas_equalTo equalTo(MASBoxValue((__VA_ARGS__)))#define mas_greaterThanOrEqualTo greaterThanOrEqualTo(MASBoxValue((__VA_ARGS__)))#define mas_lessThanOrEqualTo lessThanOrEqualTo(MASBoxValue((__VA_ARGS__)))#define mas_offset valueOffset(MASBoxValue((__VA_ARGS__)))#ifdef MAS_SHORTHAND_GLOBALS#define equalTo mas_equalTo(__VA_ARGS__)#define greaterThanOrEqualTo mas_greaterThanOrEqualTo(__VA_ARGS__)#define lessThanOrEqualTo mas_lessThanOrEqualTo(__VA_ARGS__)#define offset mas_offset(__VA_ARGS__)

代入上述宏定义,前边的代码等效成:

make.edges.equalTo(MASBoxValue(UIEdgeInsetsMake(0.0f, 0.0f, 0.0f, 0.0f)));

能够发掘,其实在那之中调用的是 MASBoxValue 这一个宏,它将 C 和 Objective-C 语言中的一些主干数据结构譬如说 double CGPoint CGSize 那个值用 NSValue 进行打包。

这里还帮忙直接调用 size、center 等,具体贯彻都大概,就不熬述了:

make.center.equalTo(CGPointMake;make.size.equalTo(CGSizeMake);

3.3 make.height.equalTo(@[redView, blueView])

make.height.equalTo(@[redView, blueView])

再来看看这种传数组的,在走到 .equalTo 时,最后会调用 MASViewConstraint.m 里面包车型大巴 equalToWithRelation 方法

  • MASConstraint.m
- (MASConstraint * equalTo { return ^id(id attribute) { return self.equalToWithRelation(attribute, NSLayoutRelationEqual); };}
  • MASViewConstraint.m
- (MASConstraint * (id, NSLayoutRelation))equalToWithRelation { return ^id(id attribute, NSLayoutRelation relation) { if ([attribute isKindOfClass:NSArray.class]) { NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation"); NSMutableArray *children = NSMutableArray.new; for (id attr in attribute) { MASViewConstraint *viewConstraint = [self copy]; viewConstraint.layoutRelation = relation; viewConstraint.secondViewAttribute = attr; [children addObject:viewConstraint]; } MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children]; compositeConstraint.delegate = self.delegate; [self.delegate constraint:self shouldBeReplacedWithConstraint:compositeConstraint]; return compositeConstraint; } else { .... } };}

那边依旧遍历数组,並且 MASViewConstraint 实现 NSCopying 协议,调用 [self copy] 会创建 MASViewConstraint 对象

- copyWithZone:(NSZone __unused *)zone { MASViewConstraint *constraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:self.firstViewAttribute]; constraint.layoutConstant = self.layoutConstant; constraint.layoutRelation = self.layoutRelation; constraint.layoutPriority = self.layoutPriority; constraint.layoutMultiplier = self.layoutMultiplier; constraint.delegate = self.delegate; return constraint;}

然后会依据传的数组里面包车型地铁 Value 类型来做差异的操作,前面讲过就不熬述了:

- setSecondViewAttribute:secondViewAttribute { if ([secondViewAttribute isKindOfClass:NSValue.class]) { [self setLayoutConstantWithValue:secondViewAttribute]; } else if ([secondViewAttribute isKindOfClass:MAS_VIEW.class]) { _secondViewAttribute = [[MASViewAttribute alloc] initWithView:secondViewAttribute layoutAttribute:self.firstViewAttribute.layoutAttribute]; } else if ([secondViewAttribute isKindOfClass:MASViewAttribute.class]) { _secondViewAttribute = secondViewAttribute; } else { NSAssert(NO, @"attempting to add unsupported attribute: %@", secondViewAttribute); }}

最后正是生成 MASCompositeConstraint 对象,并通过 delegate 方式,调用 MASConstraintMaker 的方法,替换 self.constraints 数组里的自律:

- constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint { NSUInteger index = [self.constraints indexOfObject:constraint]; NSAssert(index != NSNotFound, @"Could not find constraint %@", constraint); [self.constraints replaceObjectAtIndex:index withObject:replacementConstraint];}

4.1 简化的设计情势:工厂类&工厂方法

MASConstraintMaker类便是三个厂子类,负担创立MASConstraint花色的对象(依赖于MASConstraint接口,而不借助于实际实现)。在UIView的View+MASAdditions分拣中就是调用的MASConstraintMaker类中的一些主意。上述大家在使用Masonry给subView加多封锁时,mas_makeConstraints情势中的Block的参数正是MASConstraintMaker的目的。顾客能够透过该Block回调过来的MASConstraintMaker对象给View钦命要加上的自律以及该约束的值。该工厂中的constraints质量数组就记录了该工厂创造的有所MASConstraint对象。

图片 12主旨类和分类的类图

MASConstraintMaker 之所以成为约束工厂类,因为MASConstraintMaker赋值创造NSLayoutConstraint对象,因为Masonry将NSLayoutConstraint类进一步封装成了MASViewConstraint,所以MASConstraintMaker是背负创设MASViewConstraint的对象,并调用MASViewConstraint对象的Install办法将该约束增多到相应的视图中。

说了如此多,总括一下,即便您调用maker.top, maker.left等等那么些艺术都会调用下方的工厂方法来成立相应的MASViewConstraint目的,并记下在工厂对象的约束数组中。之所以能链式调用,正是讲当前的厂子对象(MASConstraintMaker)指定为MASViewConstraint目的的代理,所以贰个MASViewConstraint目标就能够通过代办来调用工厂方法来创立另二个新的MASViewConstraint目的了,此处用到了代理形式。

图片 13厂子对象MASConstraintMaker的工厂方法

剧中人物分析

  • Client:UIView,通过分类View+MASAdditions来扮演

  • 工厂类:MASConstraintMaker

  • 虚幻产品:MASConstraint

  • 实际产品:MASViewConstraintMASCompositeConstraint

图片 14工厂类与四个子类

4.2 真正的设计形式:组合方式

换一种角度看,Masonry 而不是单纯的工厂格局,而是利用了杰出的 Composite 设计方式,普通话可译作结缘方式

图片 15典型的 Composite 类图图片 16规范的 Composite 对象协会

4.2.1 经典 组合情势 中的出席者:
Client
  • 透过 Component 接口操纵组合部件的指标。
Component
  • 为组合中的对象注解接口。
  • 在适宜的动静下,落成全部类共有接口的缺省级银行为
  • 宣称二个接口用于访问和治本 Component 的子组件。
  • 在递总结构中定义三个接口,用于访谈一个父部件,并在适当的情事下促成它。
Leaf
  • 在重组中意味着叶节点对象,叶节点未有子节点。
  • 在组合中定义图元对象的作为。
Composite
  • 概念有子部件的那个部件的一颦一笑。
  • 在 Composite 接口中完结与子部件有关的操作。
4.2.2 从 构成方式 的角度看,Masonry 框架中的角色分析:

UIView,通过分类View+MASAdditions来调用Masonry

Client
  • MASConstraintMaker
Component
  • MASConstraint
Leaf
  • MASViewConstraint
Composite
  • MASCompositeConstraint

4.3 编制程序观念:链式编制程序

Objective-C是一门动态语言,它采用了一种动态的消息发送机制,即对象或类调用方法。而OC中的点语法则只好通过setter和getter方法功效于类的属性,而无法功用于有个别方法。想达成链式语法,只好通过类似block属性的getter方法。

链式编制程序思想:核心绪想为将block作为艺术的重返值,且重返值的类别为调用者本人,并将该措施以setter的方式再次来到,那样就足以兑现了连年调用,即为链式编制程序。

总结利用链式编制程序思想贯彻一个粗略总括器的机能:

4.3.1 新建四个名字为CaculateMaker的类,用于运算。

图片 17新建三个名称为CaculateMaker的类

4.3.2 在CaculateMaker.h文件中扬言贰个方法add:
  • CaculateMaker.h
// CaculateMaker.h// ChainBlockTestApp#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>@interface CaculateMaker : NSObject@property (nonatomic, assign) CGFloat result;- (CaculateMaker *(CGFloat num))add;@end
4.3.3 在CaculateMaker.m文件中落到实处那几个点子:
  • CaculateMaker.m
// CaculateMaker.m// ChainBlockTestApp#import "CaculateMaker.h"@implementation CaculateMaker- (CaculateMaker *(CGFloat num))add;{ return ^CaculateMaker *(CGFloat num){ _result += num; return self; };}@end
4.3.4 在viewController里面导入CaculateMaker.h文件,然后调用add方法就造成了链式语法:
  • ViewController.m
CaculateMaker *maker = [[CaculateMaker alloc] init];maker.add.add;

经过地点Masonry布局能够看出,它为UIView写了三个category,扩充了mas_makeConstraints方法,并将MASConstraintMaker指标作为block的参数字传送递,在block的兑现里产生UIView的布局,提现了函数式编程思想

4.3.5 相同,大家也能够给NSObject增加贰个NSObject+Caculate的归类,实现加法操作:
  • NSObject+Caculate.h
// NSObject+Caculate.h// ChainBlockTestApp#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#import "CaculateMaker.h"@interface NSObject - caculate:(CaculateMaker *make))block;@end
  • NSObject+Caculate.m
// NSObject+Caculate.m// ChainBlockTestApp#import "NSObject+Caculate.h"@implementation NSObject - caculate:(CaculateMaker *make))block;{ CaculateMaker *make = [[CaculateMaker alloc] init]; block; return make.result;}@end
4.3.6 最后在viewController里面调用,就很轻松的落到实处了链式语法:
  • ViewController.m
CGFloat result = [NSObject caculate:^(CaculateMaker *maker) { maker.add.add.add;}];NSLog(@"结果为:%.2f",result);
  • Masonry解析

  • 厂子情势

  • 整合格局

  • 链式编制程序

版权声明:本文由大奖888-www.88pt88.com-大奖888官网登录发布于大奖888官网登录,转载请注明出处:这篇文章就是针对,对MLChainContainer文件解锁