?
如图上图所示,居于中心的是ConstraintDescription,它用来生成Constraint,最后再转换成系统的NSLayoutConstraint。 
ConstraintDescription
包含约束必备的所有因素
internal let item: LayoutConstraintItem
    internal var attributes: ConstraintAttributes
    internal var relation: ConstraintRelation? = nil
    // 记录产生约束的位置
    internal var sourceLocation: (String, UInt)? = nil
    // 标签
    internal var label: String? = nil
    internal var related: ConstraintItem? = nil
    internal var multiplier: ConstraintMultiplierTarget = 1.0
    internal var constant: ConstraintConstantTarget = 0.0
    internal var priority: ConstraintPriorityTarget = 1000.0 
当前的item(一般是UIView) 的什么属性 attributes 要和哪个目标(related)发生什么关系(relation),优先级是什么(priority),具体要怎么发生关系(multiplier,constant)
Constraint
SnapKit的约束对象,用于生成NSLayoutConstraint。
 仅通过 ConstraintDescription 生成。
LayoutConstraintItem
即被约束的对象,在iOS开发中,即为UIView。
 通过关联对象的方法,持有了很多Constraint
private var constraintsSet: NSMutableSet {
    let constraintsSet: NSMutableSet
    
    if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet {
        constraintsSet = existing
    } else {
        constraintsSet = NSMutableSet()
        objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
    return constraintsSet
    
} 
也有add(constraints)、remove(constraints) 等方法,但是仅供框架内部调用。 
ConstraintItem
被约束的对象+被约束的属性。
 ??,它有一个weak属性,一般指向了UIView,避免了循环引用。
 这个类,在创建约束时,被大量使用。 
ConstraintMaker
它提供了静态方法来创建ConstraintDescription,然后根据ConstraintDescription 来生成Constraint。 
ConstraintViewDSL
即我们调用的snp。它并不是UIView的存储属性,和函数调用更加接进。每一次调用snp,都会生成一个ConstraintViewDSL 结构体。
public extension ConstraintView {
    ...    
    public var snp: ConstraintViewDSL {
        return ConstraintViewDSL(view: self)
    }
} 
它提供了我们常用的方法,比如makeConstraints、updateConstraints、prepareConstraints等。
 这些方法,最终都调用了ConstraintMaker 的方法,来生成约束。 
ConstraintDSL 协议
被ConstraintViewDSL遵守,用来产生各种ConstraintItem,从而生成约束。 
