OC | 链式API学习

作者: Lol刀妹 | 来源:发表于2018-03-23 11:38 被阅读482次

    实际开发中常见的链式API

    使用masonry时经常会见到链式API,如

    [@[mvcButton, mvvmButton] mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(@100);
        make.right.equalTo(self.view).offset(-100);
    }];
    

    中的:

    make.right.equalTo(self.view).offset(-100);
    

    链式API由“点”链接而成,“点”的出现说明这里可能有三种情况:

    1. 后者是前者的属性
    2. 调用了get方法
    3. 调用了set方法

    很显然这里没有调用set方法。

    那么上面那句代码就可以理解为:

    1. make的属性的属性怎么怎么了...
    2. make调用get方法再调用get方法...
    3. make的属性调用get方法...

    分析masonry

    为了弄清楚到底属于哪种情况,来看一下masonry源码:

    先看make.right

    makeMASConstraintMaker类的对象

    MASConstraintMaker.h可以看到:

    @property (nonatomic, strong, readonly) MASConstraint *right;
    

    MASConstraintMaker.m可以看到:

    - (MASConstraint *)right {
        return [self addConstraintWithLayoutAttribute:NSLayoutAttributeRight];
    }
    

    也就是说right是make的属性,make.right调用了重写后的get方法,返回一个MASConstraint对象

    再看right.equalTo(self.view)

    MASConstraint.h中并没有equleTo这个属性,但是有一个方法:

    /**
     *  Sets the constraint relation to NSLayoutRelationEqual
     *  returns a block which accepts one of the following:
     *    MASViewAttribute, UIView, NSValue, NSArray
     *  see readme for more details.
     */
    - (MASConstraint * (^)(id attr))equalTo;
    

    MASConstraint.m中可以看到这个get方法被重写:

    - (MASConstraint * (^)(id))equalTo {
        return ^id(id attribute) {
            return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
        };
    }
    

    这个方法的返回值是一个block:MASConstraint * (^)(id attr),而这个block的返回值也是MASConstraint对象。

    同样的,.offset(-100)也是调用了一个重写后的get方法,返回的一个block,这个block的返回值同样是MASConstraint对象:

    /**
     *  Modifies the NSLayoutConstraint constant
     */
    - (MASConstraint * (^)(CGFloat offset))offset;
    
    - (MASConstraint * (^)(CGFloat))offset {
        return ^id(CGFloat offset){
            self.offset = offset;
            return self;
        };
    }
    

    完整解读

    make.right.equalTo(self.view).offset(-100);可以理解为:

    makeright属性(MASConstraint对象)调用了重写后的get方法equleTo,返回经过处理后的MASConstraint对象,再调用get方法offset,返回再次经过处理的MASConstraint对象。

    如何仿写链式API?

    经过上述分析可知链式API的关键在于:

    1. 重写get方法
    2. get方法的返回值是一个block
    3. 这个block的返回值是原对象,这样就可以将get方法一直执行下去了

    基于此,我仿写了一个,最终的效果是:

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        Dog *dog = [[Dog alloc] init];
        dog.weight = 100; // 最初有100斤
        
        NSLog(@"dog当前体重:%ld", dog.weight);
        
        // 注:dog每跑一千米体重减一斤,每吃一pound体重增加一斤
        dog.eat(10).run(12).run(34).eat(5).eat(1).eat(3).eat(4);
        
        NSLog(@"dog当前体重:%ld", dog.weight);
    }
    

    Dog.h文件:

    #import <Foundation/Foundation.h>
    
    @class Dog;
    typedef Dog *(^RunBlock)(NSInteger distance);
    typedef Dog *(^EatBlock)(NSInteger pound);
    
    @interface Dog : NSObject
    
    @property (nonatomic, assign) NSInteger weight;
    
    - (RunBlock)run;
    - (EatBlock)eat;
    
    @end
    

    Dog.m文件:

    #import "Dog.h"
    
    @implementation Dog
    
    - (RunBlock)run {
        return ^(NSInteger distance) {
            // 每次run,体重相应减少
            self.weight -= distance;
            return self;
        };
    }
    
    - (EatBlock)eat {
        return ^(NSInteger pound) {
            // 每次eat,体重相应增加
            self.weight += pound;
            return self;
        };
    }
    
    @end
    
    

    demo

    https://github.com/CaiWanFeng/ChainProgramming

    以上就是我对链式API的理解,若有差池,欢迎指出。

    相关文章

      网友评论

      本文标题:OC | 链式API学习

      本文链接:https://www.haomeiwen.com/subject/ynwaqftx.html