iOS鏈式程式設計及函數語言程式設計

西門吹霧發表於2018-01-08

提到鏈式程式設計和函數語言程式設計,最典型的代表是Masonry 比較完美的實現了函數語言程式設計和鏈式程式設計。例如

[view mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self.view).offset(100);
        make.centerX.equalTo(self.view.mas_centerX).offset(100);
        make.height.mas_equalTo(100);
        make.width.mas_equalTo(100);
    }];
複製程式碼

所謂的鏈式程式設計其實就是 在返回值的基礎上繼續呼叫方法,那麼問題來了。什麼樣的返回值才能呼叫方法,答案是返回物件 只要返回物件然後呼叫對應的物件方法即可實現 鏈式程式設計

例如 : 首先定義Person類 新增兩個物件方法

-(void)play;

-(void)run;
複製程式碼
-(void)play{
    NSLog(@"play");
}
-(void)run{
    
    NSLog(@"run");
}
複製程式碼

ViewController呼叫

 Person * xiaoming = [Person new];
 [xiaoming play];
複製程式碼

我們現在想要實現的是 [[xiaoming play]run],所以play方法返回值就不能為空,應該是Person物件

-(Person *)play;

-(Person *)play{
    
    return self;
}
複製程式碼

我們已經實現了[[xiaoming play]run]

這樣的鏈式程式設計 和Masonry 確實有點相差甚遠 我們知道在OC中的方法呼叫是 傳送訊息的方式實現的那麼 要實現 person.eat 該怎麼實現呢? 那麼我們如何實現.方法呢

-(void(^)(void))play2;
複製程式碼
-(void (^)(void))play2{
    
    return ^(){
        NSLog(@"play2");
    };
}
複製程式碼

即可實現 [xiaoming play].play2();

然而後邊如果想要新增點方法,實現方法相同,只需返回均為Person物件即可。

-(Person *(^)(NSString * str))play2;
-(void(^)(NSString * str))play3;
複製程式碼
- (Person *(^)(NSString *str))play2{
    
    return ^(NSString *str){
        
        NSLog(@"%@",str);
        return self;
    };
}
-(void (^)(NSString * str))play3{
    
    return ^(NSString * str){
        NSLog(@"%@",str);
    };
}
複製程式碼

即可實現xiaoming.play2(@"33").play3(@"333");

上面的方法是通過block返回值為當前物件,即可實現點語法連續呼叫。

構造方法

函數語言程式設計 就是通過類似於 函式呼叫的方式實現想要的功能即 method(); 這樣的方式, 那麼我們知道在OC能用method() 這樣呼叫,只有一個可以實現,那就是BLOCK, 我們在呼叫BLOCK時 不就是這樣呼叫的嗎? 那麼我們知道只要我的一個方法的返回值是BLOCK的時候就可以使用函式式呼叫。

定義構造方法

+(instancetype)initWithP:(void(^)(Person * p))Block;
複製程式碼
+(instancetype)initWithP:(void (^)(Person *))Block{
    
    Person * p = [Person new];
    return p;
    
}
複製程式碼

可以呼叫返回值為p的函式式構造方法,然後在內部對p物件進行使用;

[Person initWithP:^(Person *p) {
        
    }];
複製程式碼

即可呼叫鏈式方法

 [Person initWithP:^(Person *p) {
          p.play2(@"222").play3(@"3333");
    }];
複製程式碼

定義成員屬性實現點語法

上面均是通過定義方法實現點語法呼叫,但是我們的程式設計習慣的用點語法調取類的成員屬性。OC中的點語法,.XXgetter.XX=XXX;是setter,顯然鏈式程式設計是一串的,所以我們應該想到將block宣告為屬性,並且在這些block屬性的getter方法中做一些事情。

person類新增成員屬性

@property(nonatomic,readonly,copy)Person *(^eat)(NSString * str);
複製程式碼

重寫成員屬性getter方法

-(Person *(^)(NSString *))eat{
    
    return ^(NSString* eat){
        NSLog(@"%@",eat);
        return self;
        
    };
    
}
複製程式碼

所以我們就可以實現點呼叫eat方法。

    [Person initWithP:^(Person *p) {
         p.play2(@"222").eat(@"333").play3(@"444");
    }];
複製程式碼

定義屬性相比定義方法一個突出的優點就是輸入的時候會有輸入提示,所以更常用。

舉例說明:

我們現在要在VC上加四個大小相同,圓角為2的紅色view,實現程式碼如下


@interface MYView : UIView
+(instancetype)initWith:(void(^)(MYView *view))BLOCK;

@property(nonatomic,readonly,copy)MYView *(^viewFrame)(CGRect  frame);
@property(nonatomic,readonly,copy)MYView * (^layerCornerRadious)(CGFloat radious);
@property(nonatomic,copy,readonly)MYView*(^ColorString)(NSString * colorStr);

@end
複製程式碼

+(instancetype)initWith:(void (^)(MYView *))BLOCK{
    MYView * view = [[MYView alloc]init];
    if (BLOCK) {
        BLOCK(view);
    }
    return view;
    
}
-(MYView *(^)(CGRect))viewFrame{
    return  ^MYView*(CGRect rect){
        self.frame = rect;
        return self;
    };
}
-(MYView *(^)(CGFloat))layerCornerRadious{
    return ^MYView*(CGFloat radious){
        self.layer.cornerRadius = radious;
        self.layer.masksToBounds = YES;
        return self;
    };
    
}

-(MYView *(^)(NSString *))ColorString{
    return ^MYView* (NSString * colorStr){
        self.backgroundColor = [UIColor redColor];
        return self;
    };
    
}
複製程式碼

只需在VC中呼叫

[self.view addSubview:[MYView initWith:^(MYView *View) {
        View.viewFrame(CGRectMake(100, 200, 20, 20)).layerCornerRadious(2).ColorString(@"顏色自己設定");
    }]];
複製程式碼

完結 demo地址:github.com/IT-iOS-xie/…

相關文章