面向對象的語言有三個特點,封裝 繼承 多態,這會說的鏈式編程是基于封裝這一特點的延伸
Masonry是iOS開發中經常使用的框架,它就是一個鏈式編程的經典例子,把控件的約束條件寫在一個block里面,一次性完成對某個控件的約束,而且使用點語法寫起來干凈瀟灑,省去了OC中最反人類的[],當然,最終使用與否還是看個人習慣以及團隊協作的便利性;
鏈式編程的思路之神奇的點語法
用過Masonry的朋友們會發現雖然里面在一次又一次的調用方法,可是卻沒有用到[],而是頻繁的用點來操作.這其實是一個開發者容易遺漏的神奇地方.
eg.
NSMutableString *mutableString = [NSMutableString string];
mutableString.copy;//1
[mutableString copy];//2
寫法1會報"property access result unused - getters should not be used for side effects"這個么一個警告,這個不受影響,因為我們現在沒有將執行結果賦給其他變量所有會有這個警告使用[]調用方法即使方法有返回值在我們不接收返回值的時候也不會出現警告.我們將寫法1寫成這樣就可以將警告消除.
(void)mutableString.copy;
就實際的使用來看,二者并沒有什么區別,那我們當然會想,這是不是Foundation框架在內部進行了什么處理才可以這樣調用了,于是我們照葫蘆畫瓢.
- (void)hehe{
NSLog(@"123,hehe");
}
- (void)viewDidLoad {
[super viewDidLoad];
(void)self.hehe;
}
控制臺結果是
[25253:1097886] 123,hehe
這么一來我們的鏈式編程點語法就的秘密就解開了.由于鏈式點語法的返回值我們每次都會循環使用(實際上返回值是一個返回值為self的block),所以我們也不會看到鏈式點語法中(void)的出現.
奇葩的返回值
大家一定都多多少看過Masonry框架的底層代碼,可以看到每次點語法的調用返回的總是一個約束.
eg.
- (MASConstraint *)edges
- (MASConstraint * (^)(id))equalTo
調用的的時候是
make.edges.mas_equalTo(0);
所以單純返回一個可以循環調用的類型就可以進行基本的鏈式編程了,可是如果要接參,沒辦法,我們只能把返回值類型寫成==>帶參數的返回值為可循環類型的block.
開工-來一個小demo
#import <UIKit/UIKit.h>
@class JJButton;
typedef JJButton *(^JJButtonStringBlock)(NSString *aName);//typedef一個返回值為JJButton* 參數為NSString* 的名字為JJButtonStringBlock的block,方便以后快速定義該類型block
typedef JJButton *(^JJButtonIntegerBlcok)(NSUInteger aNumber);
typedef JJButton *(^JJButtonColorBlock)(UIColor *aColor);
@interface JJButton : UIButton
- (JJButtonStringBlock)imageName;
- (JJButtonStringBlock)title;
- (JJButtonIntegerBlcok)titleFont;
- (JJButtonColorBlock)textColor;
+ (JJButton *)makeJJButton:(void (^)(JJButton *))block;//該方法為工廠方法,能夠快速創建一個JJButton,在一個參數為block的方法中一次性設置好你需要的JJButton
@end
不多說了,下面是方法的實現
#import "JJButton.h"
@implementation JJButton
- (JJButtonStringBlock)imageName{
return ^JJButton *(NSString *aName){
[self setImage:[UIImage imageNamed:aName] forState:UIControlStateNormal];
NSLog(@"imageName");
return self;
};
}
- (JJButtonStringBlock)title{
return ^JJButton *(NSString *aName){
[self setTitle:aName forState:UIControlStateNormal];
NSLog(@"title");
return self;
};
}
- (JJButtonIntegerBlcok)titleFont{
return ^JJButton *(NSUInteger aNumber){
self.titleLabel.font = [UIFont systemFontOfSize:aNumber];
NSLog(@"titleFont");
return self;
};
}
- (JJButtonColorBlock)textColor{
return ^JJButton *(UIColor *aColor){
[self setTitleColor:aColor forState:UIControlStateNormal];
NSLog(@"textColor = %@",aColor);
return self;
};
}
+ (JJButton *)makeJJButton:(void (^)(JJButton *))block{
JJButton * button = [[JJButton alloc] init];
block(button);
return button;
}
@end
調用
JJButton *myButton = ({
JJButton *button = [[JJButton alloc] init];
button.title(@"heiheihei").imageName(@"3").titleFont(15).textColor([UIColor blackColor]);
button.frame = CGRectMake(100, 100, 100, 100);
[button addTarget:self action:@selector(didClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
button;
});
上訴方法是不適用工廠方法的調用,我使用了GCC語法,這種語法看上去比較規整.
下面是工廠方法
[JJButton makeJJButton:^(JJButton *button) {
button.title(@"xixixi").imageName(@"abc").titleFont(20).textColor([UIColor orangeColor]);
button.frame = CGRectMake(100, 250, 100, 100);
[self.view addSubview:button];
[button addTarget:self action:@selector(didClick:) forControlEvents:UIControlEventTouchUpInside];
}];
這種方法大家應該就分廠熟悉了,它與Masonry那種鏈式編程寫法非常相似了,在工廠方法中我們在類方法內部進行了初始化,相當于進行了更加徹底的封裝.
蘿卜青菜各有所愛哈~
版權聲明:本文版權歸本文作者所有,始發于簡書,如需轉載請聯系作者,違者必究.