美文网首页
链式编程思想和响应式编程思想的学习总结

链式编程思想和响应式编程思想的学习总结

作者: 07212a79db66 | 来源:发表于2016-07-04 15:43 被阅读439次

    1.链式编程思想的代表:Masonry框架

    • 主要的特点:链式编程是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好,特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)

    2.响应式编程思想的代表:KVO的运用

    • 主要特点: 不需要考虑调用的顺序,只需要知道结果

    (一) 链式编程思想

    下面代码为使用Masonry给一个控件添加约束:

        UIView *redView = [[UIView alloc] init];
        
        redView.backgroundColor = [UIColor redColor];
        
        [self.view addSubview:redView];
            
         [redView mas_makeConstraints:^(MASConstraintMaker *make) {
             // block:把需要操作的值当做block参数,block也需要返回值,就是方法调用者
            // 设置约束
            // 给make添加left,top约束,调用equalTo给这两个约束赋值
            make.left.top.equalTo(@10);
            make.right.bottom.equalTo(@-10);
        }];
    
    • 注意:如果将[self.view addSubview:redView];这句代码写在布局后面运行程序,会挂.所以给控件添加约束之前应先把控件添加到view上面

    看到make.left.top.equalTo(@10); 这样的写法,会不会觉得很方便啊. 下面大概分析一下它的执行流程:

    • 1.给所有UIView提供一个设置约束的方法mas_makeConstraints
    • 2.mas_makeConstraints方法实现:创建约束制造者,约束制造者提供了很多设置约束的方法,每个制造约束(equalTo)的方法,方法不需要参数,但是必须返回block,每个block需要传入一个参数,用于计算控件的约束。

    下面模仿Masonry实现一个计算器:

    • 1.给所有类提供一个计算方法dj_makeResult,
    • 2.创建计算制造者,计算制造者提供了很多方法计算,每个计算方法,方法不需要参数,但是必须返回block,每个block需要传入一个参数,计算值。
    • 3.传入block,block用于把所有的计算保存到计算制造者中
    • 4.执行blcok
    • 5.把计算制造者计算的值,返回出去

    创建一个计算管理者类CalculateManager,Masonry给UIView提供mas_makeConstraints方法设置约束,那暂给NSObject提供一个分类:+ (int)dj_makeResult:(void(^)(CalculateManager *manager))block;

    #import <Foundation/Foundation.h>
    @class CalculateManager;
    
    @interface NSObject (Calculate)
    + (int)dj_makeResult:(void(^)(CalculateManager *manager))block;
    @end
    
    #import "NSObject+Calculate.h"
    #import "CalculateManager.h"
    
    @implementation NSObject (Calculate)
    
    + (int)dj_makeResult:(void(^)(CalculateManager *manager))block {
        //创建计算器管理者
        CalculateManager *manager = [[CalculateManager alloc] init];
        block(manager);
        return manager.result;
    }
    
    @end
    
    #import <Foundation/Foundation.h>
    
    @interface CalculateManager : NSObject
    
    /** 保存计算结果*/
    @property (nonatomic, assign) int result;
    
    - (CalculateManager *(^)(int))add;
    - (CalculateManager *(^)(int))sub;
    - (CalculateManager *(^)(int))muilt;
    - (CalculateManager *(^)(int))divide;
    @end
    
    
    #import "CalculateManager.h"
    
    @implementation CalculateManager
    
    - (CalculateManager *(^)(int))add {
        return ^CalculateManager *(int value) {
            self.result += value;
            return self;
        };
    }
    
    -(CalculateManager *(^)(int))sub {
        return ^CalculateManager *(int value) {
            self.result -= value;
            return self;
        };
    }
    
    - (CalculateManager *(^)(int))muilt {
        return ^CalculateManager *(int value) {
            self.result *= value;
            return self;
        };
    }
    
    - (CalculateManager *(^)(int))divide {
        return ^CalculateManager *(int value) {
            self.result /= value;
            return self;
        };
    }
    
    @end
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        
      int result = [NSObject dj_makeResult:^(CalculateManager *manager) {
    
           manager.add(10).divide(10);
       }];
        
       NSLog(@"%d",result);
    }
    
    

    总结:链式编程是将多个操作(多行代码)通过点号(.)链接在一起成为一句代码,使代码可读性好,特点:方法的返回值是block,block必须有返回值(本身对象),block参数(需要操作的值)

    (二) 响应式编程思想

    1. KVO的简单说明
      KVO全称是Key-value observing,当一个类的某个属性值发生变化的时候(比如数据类),需要另外一个类的某个属性(比如视图类)的某个属性做出相应的变化,这个时候我们就运用KVO来实现这样的需求.首先要注册监听,监听某个类里面属性的值,然后重写- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context方法,在这个方法里面做一些操作.

    2.键值观察是如何实现的:
    下面通过一个例子说明
    新建一个Person类,提供一个属性name

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    {
        @public
        NSString *_name; //便于外面访问成员变量
    }
    @property (nonatomic, strong) NSString *name;
    @end
    
    #import "ViewController.h"
    #import "Person.h"
    
    @interface ViewController ()
    @property (nonatomic, strong) Person *person;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        Person *p = [[Person alloc] init];
        _person = p;
        [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
         NSLog(@"person的name值改变了:%@",_person.name);
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
         //_person.name = @"张三";
        _person -> _name = @"张三";
    }
    
    @end
    

    当这样写的时候 _person -> _name = @"张三";并没有输出.
    修改为:_person.name = @"张三"; 此时控制台有打印信息,监听到name值得变化.

    结论:如果仅是直接修改属性对应的成员变量是无法实现KVO的,而_person.name这样写会调用name的setter方法.

    运行程序,继续



    观察此时p对象的isa指针指向的并不是person类,而是系统自定义的 NSKVONotifying_Person子类

    总结:KVO的本质就是监听一个对象有没有调用set方法,它的实现原理就是:当某个类对象被观察时,系统会在运行期动态的创建该类的一个派生类(子类),然后在子类中重写父类中任何被观察属性的 setter 方法。子类在被重写的 setter 方法时实现真正的通知机制.正如前面看到的那样,直接修改属性对应的成员变量并不会调用setter方法,所以无法实现KVO.与此同时系统将这个对象的isa指针指向子类,因此p对象就成为子类的对象了,重写setName,在内部恢复父类做法,通知观察者.

    通过以上的了解,下面自定义KVO的实现,对person的name进行监听:
    1 > 首先自定义NSKVONotifying_Person子类
    2 > 重写setName,在内部恢复父类做法,通知观察者
    3 > 如何让外界调用自定义Person类的子类方法,修改当前对象的isa指针,指向NSKVONotifying_Person

    第一步:给NSObject新增一个分类:

    #import <Foundation/Foundation.h>
    
    @interface NSObject (KVO)
    - (void)dj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
    @end
    
    #import "NSObject+KVO.h"
    #import "objc/message.h"
    #import "DJKVONotifying_Person.h"
    
    NSString *const observerKey = @"observer";
    
    @implementation NSObject (KVO)
    
    - (void)dj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
        //外界调用自定义Person类的子类方法,通过运行时修改当前对象的isa,指向DJKVONotifying_Person
        
        // 把观察者保存到当前对象
        objc_setAssociatedObject(self, (__bridge const void *)(observerKey), observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        // 修改对象isa指针
        object_setClass(self, [DJKVONotifying_Person class]);
    }
    @end
    
    #import "DJKVONotifying_Person.h"
    #import <objc/message.h>
    extern NSString *const observerKey;
    @implementation DJKVONotifying_Person
    - (void)setName:(NSString *)name {
        [super setName:name];
        // 通知观察者调用observeValueForKeyPath
        // 需要把观察者保存到当前对象
        // 获取观察者
        id obsetver = objc_getAssociatedObject(self, observerKey);
        [obsetver observeValueForKeyPath:@"name" ofObject:self change:nil context:nil];
    }
    @end
    

    运行程序:


    运行程序,可以看到isa指针指向了自定义的DJKVONotifying_Person类,并且也能监听name的变化.


    相关文章

      网友评论

          本文标题:链式编程思想和响应式编程思想的学习总结

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