Masonry源码分析与链式编程

在ios开发中,Masonry是最常用的第三方开发布局框架。Masonry是基于自动布局技术实现的,所以说MasonryNSLayoutConstrait的简易封装版本,底层还是封装系统的NSLayoutConstraint来实现的。下面的代码就是一段典型的布局代码:

[self.bgView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(@10);
        make.left.right.bottom.mas_equalTo(self);
    }];

基于以上代码,从源码分析看这个框架是如何实现自动布局的,以及如何实现链式编程的。

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

mas_makeConstraints执行流程
1.Autoresizing有可能会和autolayout产生冲突,所以第一件事情就是关闭Autoresizing
2.紧接着会创建一个constraintMaker,可以把它称之为约束制造者。MASConstraintMaker的初始化方法如下,

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

约束制造者内部会绑定目标view,并且生成一个可变数组用来保存约束constraint。
3.执行传入的block更新具体的约束信息。
4.让约束制造者安装约束[constraintMaker install]。安装的步骤是放在block执行之后,这也很好理解,需要外界更新了具体的约束,约束制造者才能够去安装约束。
[constraintMaker install]代码如下:

- (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;
}

这里面主要做了两件事情,清空之前的约束,将block执行时更新的约束install一遍。就是清楚老约束,安装新约束。 MASConstraintinstall实例方法就是具体的添加约束的逻辑,这个部分的代码简单理解他的工鞥就是封装系统的NSLayoutConstraint,实现添加自动布局的约束的逻辑。

以上就是使用Masonry给一个视图添加约束的大致步骤,这么看来逻辑并不是很复杂。但这不是Masonry的重点,接下来来看一下约束制造者是如何更新约束的make.left.right.bottom.equalTo(self);

//添加一个left约束属性
- (MASConstraint *)left {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    //self就是约束制造者,self的view就是绑定的视图。以下两行实现了给视图绑定约束属性。
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
    //此时传进来的是nil,先跳过暂不考虑,当使用了多个点语法时,会进入这个判断
    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;
    }
    //设置代理,constraints数组保存约束属性
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

从上述注释逻辑来看,每次调用left就是将约束添加到约束制造者的数组中。

但这句代码make.left.right.bottom.equalTo(self)是可以一直使用点语法点出接下来的right等方法,其实这就是链式编程在oc语法中的具体实现。为什么能够这样实现呢,以right为例可以看一下right的代码:

- (MASConstraint *)left {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}

它的返回值其实就是self,所以在调用了left之后,还是可以继续调用rightbottom,相当于把leftrightbottom三个约束更新到了约束数组中。这里也可以看出来链式编程的一个特点,方法返回值必须包含方法调用者

接下来再来看一下equalTo的实现:

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

make.left.right.bottom.mas_equalTo(self)也可以看出,equal_to接的是(),表示block的执行,它的返回值是一个blockname这个block后面还能够继续点出来么,答案是可以的。因为这个block的返回值还是self,仍然是方法的调用者。

Masonry中其他的更新功能大致逻辑与上面的类似,以上简要概括了约束的产生和装载的整个过程,并通过Masonry对链式编程有了了解。

你可能感兴趣的:(Masonry源码分析与链式编程)