iOS Developer

iOS 带block的KVO

2017-12-18  本文已影响0人  GlassHead

对于iOS 开发者来说,KVO(key-value-observing)的使用大家已经不再陌生,而且使用起来也是非常方便。

KVO的简单使用:

KVOObject *object = [[KVOObject alloc] init];
 [object addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
object.name = @"123";

这样我们就已经为object的name属性添加了监听,只要object的name属性发生改变,我们就可以通过KVO的回调方法获取其新值。

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
     NSLog(@"新值为 %@", [change objectForKey:NSKeyValueChangeNewKey]);
}
2017-12-18 16:44:36.096356+0800 KVO[5973:274888] 新值为 123

KVO的基本使用就是这样,那么KVO是用什么原理实现的呢?如何自己实现一个带block的KVO呢?
KVO原理:例如在为Object类添加监听时,苹果动态的为我们添加了一个类,类的名字是NSKVONotifying_Object,并且NSKVONotifying_Object是Object的子类,然后把指向Object的类指向了NSKVONotifying_Object,然后在子类中重写setter方法。

直接上代码:

-(void)sp_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context callBack:(void (^)(id _Nullable))block{
    NSString *className = [@"SP_" stringByAppendingString:NSStringFromClass([self class])];
    Class newClass = objc_allocateClassPair([self class], className.UTF8String, 0);//动态生成一个类,类名在原类基础上加一个前缀SP_
    objc_registerClassPair(newClass);//注册该类
    object_setClass(self, newClass);//把指针指向子类
    class_addMethod(newClass, @selector(setName:), (IMP)classSetName, "v@:@");//重写set方法
    objc_setAssociatedObject(self, &blockKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);//关联block对象
    
}

void classSetName(id self,SEL _cmd, NSString * newName){
    struct objc_super superClass = {
        .receiver = self,
        .super_class = class_getSuperclass(object_getClass(self))
    };
    
    // 调用父类中setter方法
    objc_msgSendSuper(&superClass,_cmd,newName);
    void(^block)(id paramter) = objc_getAssociatedObject(self, &blockKey);
    if (block) {
        block(newName);
    }
}

viewController中调用:

@interface ViewController ()
@property (nonatomic, strong) KVOObject * object;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    KVOObject *object = [KVOObject new];
    [object sp_addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil callBack:^(id  _Nullable paramter) {
        NSLog(@"block回调: %@\nobject name属性值: %@",paramter,object.name);
    }];
    _object = object;
}


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    static int a = 0;
    a++;
    _object.name = [NSString stringWithFormat:@"%d",a];
}
KVO[6404:296022] block回调: 1
object name属性值: 1
2017-12-18 17:05:34.432499+0800 KVO[6404:296022] block回调: 2
object name属性值: 2
上一篇下一篇

猜你喜欢

热点阅读