編程思想在iOS
的應用中大概有那麼幾類,咱們最經常使用的當屬於面向對象的編程思想,一切皆對象,基於這種思想離不開的就是咱們最經常使用的封裝、繼承、多態。平時工做中咱們也會接觸一些面向協議的編程思想,好比說接口分離解耦合,再好比說咱們最經常使用的delegate
都是面向協議的思想,還有就是基於ReactiveCocoa
框架也就是平時聽到的RAC提供的響應式編程思想,今天主要分析下另外一種編程思想,鏈式編程。編程
Masonry
框架做爲iOS
開發者耳熟能詳,你們在作純代碼適配的時候應該都曾用過,下面就以Masonry
爲例,但本文不過多的分析MAS
源碼,旨在提煉思想。數組
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
- (id)initWithView:(MAS_VIEW *)view {
self = [super init];
if (!self) return nil;
self.view = view;
self.constraints = NSMutableArray.new;
return self;
}
複製代碼
1.建立約束製造者MASConstraintMaker
而且綁定控件,在約束製造者init
的同時生成了一個保存全部約束的數組constraints
。bash
2.執行mas_makeConstraints
傳入的block
,返回咱們剛纔建立的約束製造者constraintMaker
。框架
3.讓約束製造者安裝約束,執行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;
}
複製代碼
其實是遍歷了咱們建立約束製造者
constraintMaker
時所建立的constraints
,constraints
裏面實際上存儲的是咱們爲控件添加的全部約束信息,而後分別對每條約束之行install
。那麼問題來了,constraints
裏面的約束從哪裏來的呢。這就要回到了上面說的第2
步,block
將約束製造者返回給用戶,讓用戶經過constraintMaker
去設置控件的約束,這些約束實際上就是存儲到了constraints
中。當執行第3
步return [constraintMaker install];
的時候,就是將全部調用者添加的佈局轉換爲NSLayoutConstraint
對象也就是咱們熟悉的純代碼適配,進行佈局更新。佈局
實際上Masonry
就是基於鏈式編程思想實現的開源框架,即強大,又直觀。好比說咱們在使用Masonry
的時候一般會這樣寫:ui
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.top.mas_equalTo(44);
make.left.mas_equalTo(5);
make.centerY.equalTo(self);
}];
複製代碼
爲何make
能夠一直這麼點下去,點語法給咱們的第一感受是get
方法,實際上確實是get
方法:spa
- (MASConstraint *)height {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeHeight];
}
複製代碼
經過源碼能夠看到.height
實際上返回的並非一個int
或者NSInteger
類型變量,而是MASConstraint
,是約束製造者自己,實際上每次調用.height就是將約束添加到咱們上面提到的constraints數組中。到這裏,鏈式編程的特色就顯而易見了,那就是方法返回值必需要有方法的調用者
。那麼還有疑問,mas_equalTo()
是什麼鬼。下面着重講一下.mas_equalTo()
,code
仍是經過源代碼點進去看一下:對象
- (MASConstraint * (^)(id))equalTo {
return ^id(id attribute) {
return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
};
}
複製代碼
返回值是一個MASConstraint * (^)(id)
的block
類型,到這裏咱們瞭解了.mas_equalTo
其實是返回了一個返回值爲MASConstraint
類型的block
,當咱們外面調用block
的時候實際上執行的是self.equalToWithRelation(attribute,NSLayoutRelationEqual);
函數,沒錯,它返回的依舊是MASConstraint
類型,依舊是方法的調用者,也就是前面提到的約束製造者,因此咱們在調用mas_equalTo()
以後還能繼續點下去,像不像個無底洞。若是這樣很差理解的話咱們能夠將添加約束的源碼改寫一下來實現:
[view mas_makeConstraints:^(MASConstraintMaker *make) {
// make.height.top.mas_equalTo(44);
MASConstraint * (^)(id)block = make.height.top.mas_equlTo;
MASConstraint *make = block(44);
make.top...
}];
複製代碼
這下應該就很好理解了。
最後總結一下什麼是鏈式編程,一句話就是方法返回值必需要有方法的調用者!