鏈?zhǔn)骄幊?/h2>

說(shuō)在前面

項(xiàng)目中用了一個(gè)第三方,其中它使用了鏈?zhǔn)骄幊?。為了封裝它,我照葫蘆畫瓢,寫了幾個(gè)分類方法。但是其中有點(diǎn)技術(shù)點(diǎn)不是很清楚,在這里簡(jiǎn)單記錄下。

本篇博客討論以下幾點(diǎn):

  • 1.原則:鏈?zhǔn)骄幊谭祷刂凳且粋€(gè)Block,Block的返回值是類的實(shí)例對(duì)象
  • 2.maker.sub(123).add(25)的調(diào)用過(guò)程是怎樣的
  • 3.為什么單獨(dú)寫maker.sub(123)不會(huì)警告,而直接寫maker.count會(huì)警告
  • 4.更優(yōu)的鏈?zhǔn)骄幊虒懛?/li>
  • 5.鏈?zhǔn)骄幊虒?shí)際應(yīng)用

1.原則:鏈?zhǔn)骄幊谭祷刂凳且粋€(gè)Block,Block的返回值是類的實(shí)例對(duì)象

先來(lái)個(gè)加減乘除的Demo

//.h文件
#import <Foundation/Foundation.h>

@interface CPMaker : NSObject

@property (nonatomic, assign) double result;

- (CPMaker *(^)(double))add;
- (CPMaker *(^)(double))sub;
- (CPMaker *(^)(double))multi;
- (CPMaker *(^)(double))divide;

- (CPMaker *)test;
- (NSInteger)count;

@end
//.m文件
#import "CPMaker.h"

@implementation CPMaker

- (CPMaker *(^)(double))add
{
    return ^(double num) {
        self.result += num;
        return self;
    };
}

- (CPMaker *(^)(double))sub
{
    return ^(double num) {
        self.result -= num;
        return self;
    };
}

- (CPMaker *(^)(double))multi
{
    return ^(double num) {
        self.result *= num;
        return self;
    };
}

- (CPMaker *(^)(double))divide
{
    return ^(double num) {
        if (num == 0.0) {
            NSAssert(num != 0.0, @"divide num should not equal zero");
            return self;
        }
        self.result /= num;
        return self;
    };
}

- (CPMaker *)test
{
    NSLog(@"%s",__func__);
    return self;
}

- (NSInteger)count
{
    return 5;
}

@end
//實(shí)際調(diào)用過(guò)程
void maker()
{
    CPMaker *maker = [CPMaker new];
    double result = maker.add(5).sub(42).multi(12).divide(23).result;
    maker.sub(12);
    NSLog(@"result = %f",result);
}

CPMaker要通過(guò)鏈?zhǔn)骄幊?,調(diào)用的對(duì)象函數(shù)返回值必須是Block,同時(shí)該Block的返回值必須是CPMaker的實(shí)例對(duì)象,也就是self。


2.maker.sub(123).add(25)的調(diào)用過(guò)程是怎樣的

鏈接地址

為之精髓.jpg

如上所示

maker.sub(123)  //一共執(zhí)行了兩步操作
可以理解為:

CPMaker *(^sub)(double) = [make sub];//1.獲取Block
subBlock(23);//2.執(zhí)行有參數(shù)的Block

所以我們直接寫maker.sub(123)是不會(huì)報(bào)錯(cuò)或警告的。
maker.sub(123).add(25) 也就不難理解了。

為什么返回值是Block?
唯有返回值是Block,在調(diào)用的時(shí)候才會(huì)有maker.add(5).sub(42)這樣的寫法。
即可以帶參數(shù)。
如果返回值不是Block,類似于test方法,寫法就是(void)maker.test.test.test;樣式,看著都別扭。如果不加(void)會(huì)警告,顯示get方法沒(méi)有使用起返回值,雖然警告但是可以正常執(zhí)行。

為什么Block返回值是CPMaker的實(shí)例對(duì)象?
當(dāng)執(zhí)行Block,返回對(duì)象本身,才可以接著調(diào)用其他的鏈?zhǔn)椒椒?,即拼接更多的方法?br> 如:maker.add(5).sub(42).multi(12).divide(23)


3.為什么單獨(dú)寫maker.sub(123)不會(huì)警告,而直接寫maker.count會(huì)警告

maker.sub(123)寫法是正確的,兩步拼成了一句話,看著有點(diǎn)難理解而已。
maker.count表示的是get方法,我們沒(méi)有用他的返回值,所以警告,但是get方法會(huì)正常調(diào)用。


4.更優(yōu)的鏈?zhǔn)骄幊虒懛?/h5>

以maker.add(23)為例,如上寫法有什么問(wèn)題?

點(diǎn)式調(diào)用沒(méi)有參數(shù)類型提示,API設(shè)計(jì)不夠友好
maker.add    

什么是更好的設(shè)計(jì)?

//.h文件對(duì)象方法全部替換成readOnly屬性(其實(shí)還是get方法)
@property (nonatomic, readonly) CPMaker *(^add)(double);
@property (nonatomic, readonly) CPMaker *(^sub)(double);
@property (nonatomic, readonly) CPMaker *(^multi)(double);
@property (nonatomic, readonly) CPMaker *(^divide)(double);

//實(shí)際調(diào)用效果有參數(shù)類型的提示
maker.add(double)

5.鏈?zhǔn)骄幊虒?shí)際應(yīng)用

實(shí)際鏈?zhǔn)骄幊讨?,如下寫法非常失?
CPMaker不該手動(dòng)創(chuàng)建并且暴露在外

void maker()
{
    CPMaker *maker = [CPMaker new];
    double result = maker.add(5).sub(42).multi(12).divide(23).result;
    NSLog(@"result = %f",result);
}

實(shí)際應(yīng)用中可能會(huì)有以下幾種情況:

1.新建容器類,提供類方法,提供鏈?zhǔn)骄幊棠芰?/p>

//.h文件
#import <Foundation/Foundation.h>
#import "CPMaker.h"

@interface CPCalculator : NSObject

//假如有參數(shù),就會(huì)有提示,Xcode新的特性
@property (nonatomic, class, readonly) CPMaker *(^calculator)(void);

@end
//.m文件
#import "CPCalculator.h"

@implementation CPCalculator

+ (CPMaker *(^)(void))calculator
{
    return ^(void){
        return [CPMaker new];
    };
}

@end

//.實(shí)際調(diào)用
CPCalculator.calculator().add(4).sub(5).multi(5).divide(23);

2.為分類提供方法,插入Block。例如Masonry

仿寫Masonry

//1.新建分類方法
#import <UIKit/UIKit.h>
#import "CPDConstraintMaker.h"

@interface UIView (CPDMasonry)

- (void)cpd_updateConstraints:(void(^)(CPDConstraintMaker *))maker;

@end
//2.CPDConstraintMaker內(nèi)部的參數(shù)
#import <Foundation/Foundation.h>
#import "CPDConstraint.h"

@interface CPDConstraintMaker : NSObject

@property (nonatomic, readonly) CPDConstraint *left;
@property (nonatomic, readonly) CPDConstraint *right;
@property (nonatomic, readonly) CPDConstraint *top;
@property (nonatomic, readonly) CPDConstraint *bottom;
@property (nonatomic, readonly) CPDConstraint *width;
@property (nonatomic, readonly) CPDConstraint *height;

@end
//3.CPDConstraint內(nèi)部比較方法
@interface CPDConstraint : NSObject

@property (nonatomic, readonly) CPDConstraint *(^cpd_equalTo)(CGFloat num);

@end
//4.實(shí)際調(diào)用
    [self.view cpd_updateConstraints:^(CPDConstraintMaker *maker) {
        maker.left.cpd_equalTo(12);
        maker.height.cpd_equalTo(4);
    }];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容