美文网首页
链式编程思想和响应式编程思想初窥

链式编程思想和响应式编程思想初窥

作者: 952625a28d0d | 来源:发表于2017-04-21 00:29 被阅读32次

    方法返回值必须有方法调用者

    Masonry

    • 创建约束制造者MASContrains,并且绑定控件,生成一个保存所有约束的数组
    • 执行Mas_makeContrains传入的Block
    • 让约束制造者安装约束
      1:清空约束
      2:添加约束
    • 返回调用者本身

    链式编程

    #import <Foundation/Foundation.h>
    #import "sumManager.h"
    
    
    @interface NSObject (sum)
    
    /**
     *  给NSObject添加一个类方法
     *
     *  @param block Block参数为sumManager
     *
     *  @return 结果
     */
    + (int)jyf_makeContraons:(void(^)(sumManager *mgr))block;
    
    @end
    
    #import "NSObject+sum.h"
    
    @implementation NSObject (sum)
    
    + (int)jyf_makeContraons:(void (^)(sumManager *))block{
        
        // 首先初始化一个sumManager
        sumManager *mgr = [[sumManager alloc] init];
        
        // Block返回mgr对象
        block(mgr);
        
        // 返回结果
        return mgr.result;
    }
    
    #import <Foundation/Foundation.h>
    
    @interface sumManager : NSObject
    
    /**
     *  结果
     */
    @property (nonatomic, assign) int result;
    
    //- (instancetype)add:(int)value;
    /**
     *  返回结果管理者Self
     */
    - (sumManager *(^)(int))add;
    
    @end
    
    #import "sumManager.h"
    
    @implementation sumManager
    
    /**
     *  实现add方法 加值之后返回Self
     */
    - (sumManager *(^)(int value))add{
        
        return ^(int value){
            _result += value;
            return self;
        };
    }
    
    @end
    

    响应式编程

    #import "ViewController.h"
    #import "Person.h"
    
    @interface ViewController ()
    
    @property (nonatomic, strong) Person *p;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        Person *p = [[Person alloc] init];
        
        // 监听name属性
        [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
        _p = p;
    }
    
    // 一旦 p对象的name属性变化 哥们就来了
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
        NSLog(@"%@",self.p.name);
    }
    
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        static int i = 0;
        i++;
        _p.name = [NSString stringWithFormat:@"%d",i];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    @end
    
    • KVC的实现过程?
      KVC的实质就是重写了属性的Set方法。。。。
      所以 在监听的时候 才会监听到。。。

    • 重写Set方法有两种情况
      1:重写分类

    • KVC底层实现
      1:自定义Person子类
      2: 重写setName方法,在内部恢复父类方法,通知观察者
      3:如何让外界调用自定义的Person子类方法?修改当前对象的isa指针,指向自定义的子类

    自定义KVP的实现过程以及思想

    • 系统的是在你检测属性的时候创建了一个KVO分类的实现的,那我们就直接写一个

    • 仿照系统写一个分类方法

    #import <Foundation/Foundation.h>
    
    @interface NSObject (JYFKVO)
    
    - (void)jyf_addObserver:(nonnull NSObject *)observer forKeyPath:(nonnull NSString *)keyPath options:(NSKeyValueObservingOptions)option context:(nullable void *)context;
    
    
    @end
    
    • 实现
    #import "NSObject+JYFKVO.h"
    
    // 因为要通知外界 所以必然要发送消息
    #import <objc/message.h>
    
    @implementation NSObject (JYFKVO)
    
    /**
     *  监听对象的某一个属性
     *
     *  @param observer 监听者
     *  @param keyPath  keyPath
     *  @param context  context
     */
    
    // self ==> 被观察者(Person)
    // observer ==> 观察者
    - (void)jyf_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)option context :(void *)context{
        /**
         1:自定义子类对象
         2:重写被监听的对象的setName,在方法中我们来调用super的,调用完毕,通知观察者
         3:修改当前对象的isa指针,让它指向我们自定义的子类!!
         */
        
        // 1:动态生成一个类
        // 1.1:创建Self的子类!第一步:获取类名
        NSString *oldClassName = NSStringFromClass([self class]);
        
        // 新的类名
        NSString *newClassName = [@"jyfKVO_" stringByAppendingString:oldClassName];
        
        // 转成C字符串
        const char * newName = [newClassName UTF8String];
        
        // 创建一个类的Class对象
        Class MyClass = objc_allocateClassPair([self class], newName, 0);
        
        // 注册类 到我们的项目中
        objc_registerClassPair(MyClass);
        
        // 2:重写Set方法 添加set方法
        // v@:@ 表示没有返回值 没有参数
        class_addMethod(MyClass, @selector(setName:), (IMP)setName, "v@:@");
        
        // 3: 修改isa指针 把self的指针 改成我们自定义的子类
        object_setClass(self, MyClass);
        
        // 4:保存观察者对象
        objc_setAssociatedObject(self, @"objc", observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    // 1:调用super的set方法
    // 2:通知我们的外界
    void setName(id self, SEL _cmd, NSString * newName){
        
        // 复写 调用super的setname方法
        
        // 保存子类类型
        id class = [self class];
        
        // 改变self的isa指针
        object_setClass(self, class_getSuperclass(class));
        
        // 调用父类的set方法
        objc_msgSend(self, @selector(setName:),newName);
        
        // 拿到观察者
        id objc = objc_getAssociatedObject(self, @"objc");
        
        // 通知观察者
        objc_msgSend(objc, @selector(observeValueForKeyPath:ofObject:change:context:),self,@"name",nil,nil);
        
        // 改回子类类型
        object_setClass(self, class);
    }
    
    @end
    
    • 在这里打断点发现 走完我们自定义的监听方法,isa指针发生了变化 已经指向了我们的子类
    Paste_Image.png
    • 使用消息机制 需要打开


      Paste_Image.png
    • 这样 我们就可以发现 能正常监听了 需要注意的是 监听完毕 需要将指针归还给旧类

    相关文章

      网友评论

          本文标题:链式编程思想和响应式编程思想初窥

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