iOS开发过程中很大一部分内容就是界面布局和跳转,iOS的布局方式也经历了 显式坐标定位方式 --> autoresizingMask --> iOS 6.0推出的自动布局(Auto Layout)的逐步优化,至于为什么推出自动布局,肯定是因为之前的方法不好用(哈哈 简直是废话),具体如何不好用以及怎么变化大家可以瞅瞅 这篇文章。iOS6.0推出的自动布局实际上用布局约束(Layout Constraint)来实现,通过布局约束(Layout Constraint)可以确定两个视图之间精确的位置的相对距离,为此,iOS6.0推出了NSLayoutConstraint来定义约束,使用方法如下:

[NSLayoutConstraint constraintWithItem:view1
  attribute:NSLayoutAttributeLeft
  relatedBy:NSLayoutRelationEqual
  toItem:view2
  attribute:NSLayoutAttributeRight
  multiplier:
  constant:]; //翻译过来就是:view1的左侧,在,view2的右侧,再多10个点,的地方。

布局约束的添加规则:

(1)对于两个同层级 view 之间的约束关系,添加到它们的父 view 上
(2)对于两个不同层级 view 之间的约束关系,添加到他们最近的共同父 view 上
(3)对于有层次关系的两个 view 之间的约束关系,添加到层次较高的父 view 上
(4)对于比如长宽之类的,只作用在该 view 自己身上的话,添加到该 view 自己上

  具体关于NSLayoutConstraint的详细使用方法参见:NSLayoutConstraint-代码实现自动布局。今天我们文章的主角——Masonry框架实际上是在NSLayoutConstraint的基础上进行封装的,这一点在后面的源码分析中我们详细解释。

1 Masonry的布局教程

  当我们需要对控件的top,bottom,left,right进行约束就特别麻烦,在OC中有一个库MasonryNSLayoutConstraint进行了封装,简化了约添加约束的方式和流程。用Masonry框架进行布局非常简单,主要特点是采用链式语法进行布局,这一点使得我们在使用和代码布局上更为方便,利用Masonry进行布局的前提条件之一是 布局视图必须先被添加到父视图中。简单示例如下代码,关于Masonry框架的使用并不是本文的重点,详情可以参见:Masonry介绍与使用实践:快速上手Autolayout。如果你的项目是Swift语言的,那么就得使用SnapKit布局框架了,SnapKit其实就是Masonry的Swift版本,两者虽然实现语言不同,但是实现思路大体一致。

UIView *sv1 = [UIView new];
//利用Masonry进行布局的前提条件之一是 布局视图必须先被添加到父视图中
[sv addSubview:sv1];
[sv1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(sv).with.insets(UIEdgeInsetsMake(, , , )); /* 等价于
make.top.equalTo(sv).with.offset(10);
make.left.equalTo(sv).with.offset(10);
make.bottom.equalTo(sv).with.offset(-10);
make.right.equalTo(sv).with.offset(-10);
*/ /* 也等价于
make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
*/
}];

2 Masonry框架源码分析

  Masonry框架是在NSLayoutConstraint的基础上进行封装的,其涉及到的内容也是非常繁多。在进行源码剖析时我们从我们经常用到的部分出发,一层一层进行解析和研究。

2.1 调用流程分析

  首先,我们先大体了解一下调用 mas_makeConstraints 进行布局时的流程步骤,其实另外两个 mas_updateConstraints 和 mas_remakeConstraints 的流程也基本上是一样的。

  • - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block 是Masonry框架中UIview + MASAdditions(UIview分类)中的方法,所以一般的控件视图都可以直接调用该方法,该方法传入一个block函数作为参数(返回值为void,参数为MASContraintMaker的实例对象make)
  • 主要布局方法 - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block 的源码和解析如下,主要工作是创建一个约束创建器,并将其传到block中(其实就是block中的make创建器)进行创建约束并返回
    @implementation MAS_VIEW (MASAdditions)
    
    - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    //关闭AutoresizingMask的布局方法是我们进行Auto Layout布局的前提步骤
    self.translatesAutoresizingMaskIntoConstraints = NO;
    //创建一个约束创建器
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    //在block中配置constraintMaker对象,即将constraintMaker传入block中(其实就是我们在block中用来添加约束的make)进行约束配置
    block(constraintMaker);
    //约束安装并以数组形式返回
    return [constraintMaker install];
    } ...
  • 约束安装方法 [constraintMaker install]; 的源代码如下,这部分的代码很简单,主要就是对当前约束创建器中的约束进行更新,因为除了我们这个 mas_makeConstraints 方法中会调用该方法之外, mas_updateConstraints 和 mas_remakeConstraints 中都会调用该方法进行约束的安装,所以在该约束安装方法中考虑了约束的删除和是否有更新等情况的处理。

    //install方法主要就是对下面这个约束数组进行维护
    @property (nonatomic, strong) NSMutableArray *constraints; - (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;
    }
  • 上面这段代码中真正添加约束的方法其实是 [constraint install]; ,这里我们要分析一下这个install到底调用的是哪个方法的install?因为这里有好几个类(MASConstraint、MASViewConstraint、MASCompositeConstraint)有install方法。要知道具体调用的是哪一个类的install方法,我们就要弄清楚这里的约束constraint到底是什么类型,这就需要我们了解约束创建器(MASConstraintMaker)中的约束数组constraints中添加的到底是什么类型的约束,经过分析(分析过程在后面会讲到)我们发现这里添加的约束是MASViewConstraint类型的,根据面向对象的多态特性,所以我们这里调用的其实就是MASViewConstraint的install方法,该方法关键代码(代码太长,只放关键性代码)如下,我们可以看到其实就是通过iOS系统自带的自动布局约束布局类NSLayoutConstraint进行布局

    - (void)install {
    if (self.hasBeenInstalled) {
    return;
    } ... //MASLayoutConstraint其实就是在NSLayoutConstraint基础上添加了一个属性而已
    //@interface MASLayoutConstraint : NSLayoutConstraint 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; ... //添加约束
    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];
    }
    }

  通过上面的分析和研究,我们基本上已经把Masonry框架中主要布局方法的主流程了解清楚了。因为这是第一次学习iOS第三方框架的源码,在这个学习过程中也走了很多弯路,最开始是从最基本的类开始看,后来发现越看越不懂,不知道这个属性的定义在什么时候用到,是什么含义((ノへ ̄、)捂脸。。。)。后来通过摸索才知道源码学习应该直接从用到的方法着手,然后一步一步深入分析源码中每一步的目的和意义,顺藤摸瓜,逐个击破

2.2 Masonry框架中的链式语法

  下面的代码是比较常用的几种Masonry的布局格式,我们可以看到都是通过点语法的链式调用进行布局的。之前在学习Java和Android的过程中接触过链式语法,在Java中要实现这种链式语法很简单,无非就是每个方法的返回值就是其本身,因为Java的方法调用是通过点语法调用的,所以很容易实现。但是在OC中,方法调用都是通过  [clazz method:parm];  的形式进行调用的,那么Masonry框架中是怎么实现的呢?

make.top.equalTo(sv).with.offset();

make.left.right.mas_equalTo(sv).mas_offset(0.0f);

make.top.left.bottom.and.right.equalTo(sv).with.insets(UIEdgeInsetsMake(, , , ));

  同样的学习方法,我们来看一下源码中各个属性或方法是怎么实现的,最重要的原因就是getter方法和Objective-C 里面,调用方法是可以使用点语法的,但这仅限于没有参数的方法

  • 首先,我们在用Masonry进行布局的时候最先用MASConstraintMaker调用一个方位属性(在MASConstraintMaker中定义了许多方位属性进行初始化调用,具体有哪些如下MASConstraintMaker.h文件中所示),用点语法调用,例如 make.top ,这时候其实是调用了其getter方法,然后在getter方法中对该约束的代理进行设置(见下MASConstraintMaker.m文件中标红注释处)

    //MASConstraintMaker.h文件
    @interface MASConstraintMaker : NSObject @property (nonatomic, strong, readonly) MASConstraint *left;
    @property (nonatomic, strong, readonly) MASConstraint *top;
    @property (nonatomic, strong, readonly) MASConstraint *right;
    @property (nonatomic, strong, readonly) MASConstraint *bottom;
    @property (nonatomic, strong, readonly) MASConstraint *leading;
    @property (nonatomic, strong, readonly) MASConstraint *trailing;
    @property (nonatomic, strong, readonly) MASConstraint *width;
    @property (nonatomic, strong, readonly) MASConstraint *height;
    @property (nonatomic, strong, readonly) MASConstraint *centerX;
    @property (nonatomic, strong, readonly) MASConstraint *centerY;
    @property (nonatomic, strong, readonly) MASConstraint *baseline; #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) @property (nonatomic, strong, readonly) MASConstraint *firstBaseline;
    @property (nonatomic, strong, readonly) MASConstraint *lastBaseline; #endif #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) @property (nonatomic, strong, readonly) MASConstraint *leftMargin;
    @property (nonatomic, strong, readonly) MASConstraint *rightMargin;
    @property (nonatomic, strong, readonly) MASConstraint *topMargin;
    @property (nonatomic, strong, readonly) MASConstraint *bottomMargin;
    @property (nonatomic, strong, readonly) MASConstraint *leadingMargin;
    @property (nonatomic, strong, readonly) MASConstraint *trailingMargin;
    @property (nonatomic, strong, readonly) MASConstraint *centerXWithinMargins;
    @property (nonatomic, strong, readonly) MASConstraint *centerYWithinMargins; #endif @property (nonatomic, strong, readonly) MASConstraint *edges;
    @property (nonatomic, strong, readonly) MASConstraint *size;
    @property (nonatomic, strong, readonly) MASConstraint *center;
    ... @end //MASConstraintMaker.m文件
    @implementation MASConstraintMaker //每个方法返回的也是MASConstraint对象,实际上是MASViewConstraint、MASCompositeConstraint类型的对象,见最后的函数中标红的注释
    - (MASConstraint *)top {
    //将对应的系统自带的约束布局的属性NSLayoutAttributeTop传入
    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) {
    //设置约束的代理是self
    newConstraint.delegate = self;
    [self.constraints addObject:newConstraint];
    }
    //返回MASViewConstraint类型的对象
    return newConstraint;
    } ... @end
  • 然后通过第一步的初始化之后返回的就是一个MASViewConstraint对象了,后面的点语法主要就在于MASViewConstraint中的属性和方法了,在MASViewConstraint的.h和.m文件中我们都没有找到top等方位相关的属性或方法,但是我们发现MASViewConstraint是继承自MASConstraint的,然后我们发现在MASConstraint中定义了大量的方位相关方法(如下代码所示),所以类似 make.top.left 前面一个top是调用MASConstraintMaker的方法,后面一个left则是通过点语法调用MASConstraint的方法。但是为什么这些方法可以进行点语法调用呢?原因就是在Objective-C 里面,调用方法是可以使用点语法的,但这仅限于没有参数的方法
    @interface MASViewConstraint : MASConstraint <NSCopying>
    //MASConstraint.h文件
    
    @interface MASConstraint : NSObject
    
    /**
    * Creates a new MASCompositeConstraint with the called attribute and reciever
    */
    - (MASConstraint *)left;
    - (MASConstraint *)top;
    - (MASConstraint *)right;
    - (MASConstraint *)bottom;
    - (MASConstraint *)leading;
    - (MASConstraint *)trailing;
    - (MASConstraint *)width;
    - (MASConstraint *)height;
    - (MASConstraint *)centerX;
    - (MASConstraint *)centerY;
    - (MASConstraint *)baseline; #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) - (MASConstraint *)firstBaseline;
    - (MASConstraint *)lastBaseline; #endif #if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (__TV_OS_VERSION_MIN_REQUIRED >= 9000) - (MASConstraint *)leftMargin;
    - (MASConstraint *)rightMargin;
    - (MASConstraint *)topMargin;
    - (MASConstraint *)bottomMargin;
    - (MASConstraint *)leadingMargin;
    - (MASConstraint *)trailingMargin;
    - (MASConstraint *)centerXWithinMargins;
    - (MASConstraint *)centerYWithinMargins; #endif ... @end
    //MASConstraint.m文件
    - (MASConstraint *)top {
    //这里会调用MASViewConstraint中的addConstraintWithLayoutAttribute:方法
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
    } //MASViewConstraint.m文件
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    NSAssert(!self.hasLayoutRelation, @"Attributes should be chained before defining the constraint relation");
    //调用代理的方法,之前我们说过设置的代理是MASConstraintMaker对象make,所以调用的实际上是MASConstraintMaker添加约束的方法,这就是我们再上面第一步讲到的方法
    return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
    } //MASConstraintMaker.m文件
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
    //当传入的constraint不为空时,即此调用不是第一个,make.toip.left在left时的调用
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
    //则用MASCompositeConstraint作为返回值,即组约束
    NSArray *children = @[constraint, newConstraint];
    MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
    //设置代理
    compositeConstraint.delegate = self;
    //重新设置
    [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
    //返回 MASCompositeConstraint对象return compositeConstraint;
    } if (!constraint) {
    //设置代理
    newConstraint.delegate = self;
    //设置约束
    [self.constraints addObject:newConstraint];
    } return newConstraint;
    }

2.3 链式语法中传参方法的调用

  在上一小节我们提到了链式语法的主要原因在于在Objective-C 里面,调用方法是可以使用点语法的,但这仅限于没有参数的方法,但是类似mas_equalTo、mas_offset等带参数传递的方法依旧可以用链式语法又是怎么一回事呢?最关键的一环就是 blockblock就是一个代码块,但是它的神奇之处在于在内联(inline)执行的时候还可以传递参数。同时block本身也可以被作为参数在方法和函数间传递。block作为参数传递很常见,就是在我们的Masonry框架中添加约束的方法 - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block 中就是讲一个block作为参数进行传递的。

  同样在MASConstraint中,我们可以看到mas_equalTo、mas_offset等带参方法的定义如下,我们可以看到,方法的定义中并没有参数,但是返回值是一个带参的block,并且该block还返回一个MASConstraint对象(MASViewConstraint或者MASCompositeConstraint对象),所以方法的定义和使用都没有什么问题,和上一小节分析的内容差不多。最主要的区别就是这里返回值为带参数的block,并且该block的参数可以通过我们的方法进行传值。关于带参block作为返回值得用法可以参见 此链接的文章

- (MASConstraint * (^)(MASEdgeInsets insets))insets;

- (MASConstraint * (^)(CGFloat inset))inset;

- (MASConstraint * (^)(CGSize offset))sizeOffset;

- (MASConstraint * (^)(CGPoint offset))centerOffset;

- (MASConstraint * (^)(CGFloat offset))offset;

- (MASConstraint * (^)(NSValue *value))valueOffset;

- (MASConstraint * (^)(CGFloat multiplier))multipliedBy;

- (MASConstraint * (^)(CGFloat divider))dividedBy;

- (MASConstraint * (^)(MASLayoutPriority priority))priority;

- (MASConstraint * (^)(void))priorityLow;

- (MASConstraint * (^)(void))priorityMedium;

- (MASConstraint * (^)(void))priorityHigh;

- (MASConstraint * (^)(id attr))equalTo;

- (MASConstraint * (^)(id attr))greaterThanOrEqualTo;
//MASConstraint.m文件
- (MASConstraint * (^)(id))mas_equalTo {
return ^id(id attribute) {
//多态调用子类MASViewConstraint或者MASCompositeConstraint的对应方法
return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
};
} //MASViewConstraint.m中对应的方法,MASCompositeConstraint其实也类似,只是循环调用每一个子约束的该方法
- (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;
}
};
}

3 Masonry框架的整体运用的理解

进过上面的原理分析,大体理解了其调用和实现眼里,接下来,我们通过下面的这句代码在容器中的演变过程来进行整体感受一下,下面的演变过程来自:Masonry源码学习,原文有几处有点小问题修改过,大家参考的时候注意甄别和判断。

make.top.right.bottom.left.equalTo(superview)
  • make.top

    • 生成对象A:MASViewConstraint(view.top)
    • 将A的delegate设为make
    • 将A放入make的constraints中,此时make.constraints = [A]
    • 返回A
  • make.top.right
    • 生成对象B:MASViewConstraint(view.right)
    • 使用A和B生成MASCompositeConstraint对象C,将C的delegate设为make
    • 将make.constraints中替换成C,此时make.constraints = [C],C.childConstraints = [A,B]
    • 返回C
  • make.top.right.bottom
    • 生成对象D:MASViewConstraint(view.bottom),将D的delegate为C
    • 将D放入C.childConstraints中,此时C.childConstraints = [A,B,D]
    • 返回C
  • make.top.right.bottom.left
    • 生成对象E:MASViewConstraint(view.left),E的delegate为C
    • 将E放入C.childConstraints中,此时C.childConstraints = [A,B,D,E]
    • 返回C
  • make.top.right.bottom.left.equalTo(superview)
    • 会依次调用A,B,D,E的equalTo(superView)

在上面的过程中可以看到:

  • 对make.constraints的添加和替换元素的操作
  • 对MASCompositeConstraint对象的添加元素的操作(当.equalTo(@[view1,view2])时就有替换操作了,在里面没体现出)。
  • 每个constraint的delegate为它的父容器,因为需要父容器来执行添加和替换约束的操作。

4 Masonry框架的整体架构

  盗用iOS开发之Masonry框架源码解析中的一张图,这张图将Masonry框架的架构阐述的很清晰,Masonry框架主要分为4个部分:

  • View+MASAdditions:最左边的红色框的这个类,这是Masonry框架最主要的一个类,主要是最下面的四个添加和修改约束的方法
  • MASConstraintMaker:中间绿色框中的这个类,这是Masonry框架中的过渡类,链接最左边和最右边之间的关系,也是链式语法的发起点和添加约束的执行点。MASConstraintMaker类就是一个工厂类,负责创建和安装MASConstraint类型的对象(依赖于MASConstraint接口,而不依赖于具体实现)。
  • 核心类:最右边的黄色框的这个类群,这是Masonry框架中的核心基础类群,这个类群又分为两个部分:
    • 约束类群:黄色框上面三个类,其中MASConstraint是一个抽象类,不可被实例化。我们可以将MASConstraint是对NSLayoutConstriant的封装,看做是一个接口或者协议。MASViewConstraint和MASCompositeConstraint都继承自MASConstraint,其中MASViewConstraint用于定义一个单独的约束,而MASCompositeConstraint则用于定义一组约束条件,例如定义size、insert等参数时返回的其实都是MASCompositeConstraint。
    • 属性类群:主要是指MASViewAttribute,主要是对NSLayoutAttribute的扩展,方便我们进行约束定义和修改
  • 附属类群:还有一些工具类没有在这张图中进行展示,例如NSArray+MASAdditions、NSLayoutConstraint+MASDebugAdditions、MASLayoutConstraint等,都定义了一些工具和简化方法。

iOS学习——布局利器Masonry框架源码深度剖析的更多相关文章

  1. iOS开发之Masonry框架源码深度解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  2. Masonry框架源码深度解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  3. iOS开发之Masonry框架源码解析

    Masonry是iOS在控件布局中经常使用的一个轻量级框架,Masonry让NSLayoutConstraint使用起来更为简洁.Masonry简化了NSLayoutConstraint的使用方式,让 ...

  4. libevent源码深度剖析三

    libevent源码深度剖析三 ——libevent基本使用场景和事件流程 张亮 1 前言 学习源代码该从哪里入手?我觉得从程序的基本使用场景和代码的整体处理流程入手是个不错的方法,至少从个人的经验上 ...

  5. libevent源码深度剖析一

    libevent源码深度剖析一 ——序幕 张亮 1 前言 Libevent是一个轻量级的开源高性能网络库,使用者众多,研究者更甚,相关文章也不少.写这一系列文章的用意在于,一则分享心得:二则对libe ...

  6. libevent源码深度剖析八

    libevent源码深度剖析八 ——集成信号处理 张亮 现在我们已经了解了libevent的基本框架:事件管理框架和事件主循环.上节提到了libevent中I/O事件和Signal以及Timer事件的 ...

  7. libevent源码深度剖析七

    libevent源码深度剖析七 ——事件主循环 张亮 现在我们已经初步了解了libevent的Reactor组件——event_base和事件管理框架,接下来就是libevent事件处理的中心部分 — ...

  8. libevent源码深度剖析六

    libevent源码深度剖析六 ——初见事件处理框架 张亮 前面已经对libevent的事件处理框架和event结构体做了描述,现在是时候剖析libevent对事件的详细处理流程了,本节将分析 lib ...

  9. libevent源码深度剖析五

    libevent源码深度剖析五 ——libevent的核心:事件event 张亮 对事件处理流程有了高层的认识后,本节将详细介绍libevent的核心结构event,以及libevent对event的 ...

随机推荐

  1. 【JAVA】SWING_ 界面风格

    在java中,界面外观的管理是由UIManager类来管理的.不同的系统上安装的外观不一样 ,默认的是java的跨平台外观. 1.获取系统所有外观 import javax.swing.*; impo ...

  2. linux(CENTOS)系统各个目录的作用详解

    Linux(CentOS)系统各个目录的作用详解 文件的类型 LINUX有四种基本文件系统类型:普通文件.目录文件.连接文件和特殊文件,可用file命令来识别. 普通文件:如文本文件.C语言元代码.S ...

  3. python云算法

    http://www.runoob.com/python3/python3-basic-operators.html 本章节主要说明Python的运算符.举个简单的例子 4 +5 = 9 . 例子中, ...

  4. 调用webService的几种方式

    转自:http://blog.csdn.net/u011165335/article/details/51345224 一.概览 方式1: HttpClient:可以用来调用webservie服务,也 ...

  5. 在 .NET中,一种更方便操作配置项的方法

    在应用程序的开发过程中,我们往往会为软件提供一些配置项,以允许软件根据配置项灵活来做事情,比如配置日志文件路径等,此外,我们还可以用配置项来为用户存储其偏好设置等. .NET 为我们默认提供了配置机制 ...

  6. 自写 zTree搜索功能 -- 关键字查询 -- 递归无限层

    唠叨一哈 前两天朋友跟我说要一个ztree的搜索功能,我劈头就是一巴掌:这种方法难道无数前辈还做少了?自己去找,我很忙~然后我默默地蹲着写zTree的搜索方法去了.为什么呢?因为我说了句“找不到是不可 ...

  7. TypeScript装饰器(decorators)

    装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为. 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被 ...

  8. 性能测试资源监控工具nmon使用方法

    1.简述  nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具,相对于其它一些系统资源监控工具来说,nmon所记录的信息是比较全面的,它能在系统运行过程中实时地捕捉系统资源的使用 ...

  9. Java学习笔记22---内部类之成员内部类的继承问题

    成员内部类可以继承其他的类,也可以被其它类继承,本文主要说明其它类继承成员内部类的问题. 本文要点如下: 1).成员内部类的子类可以是内部类,也可以不是内部类: 2).当成员内部类的子类不是内部类或子 ...

  10. Linux - ubuntu读取/root/.profile时发现错误:mesg:ttyname fa

    启动ubuntu,以root用户登陆,打开命令行终端 输入命令:#vim /root/.profile 找到.profile文件中的mesg n 将其替换成tty -s && mesg ...