KVO的Block实现和Selector实现

#import <Foundation/Foundation.h>

typedef void(^ObserverBlock)(NSDictionary *change);

@interface KVOObserver : NSObject

/*block
 *
 *object:被观察者
 */
+ (id)observerForObject:(id)object
                keyPath:(NSString *)keyPath
                options:(NSKeyValueObservingOptions)options
            changeBlock:(ObserverBlock)block;


/*selector
 *
 *object:被观察者
 *action:-(void)targetActionCallbackForObject:(id)object keyPath:(NSString*)keyPath  change:(NSDictionary*)change
 */
+ (id)observerForObject:(id)object
                keyPath:(NSString *)keyPath
                options:(NSKeyValueObservingOptions)options
                 target:(id)target
                 action:(SEL)action;
@end


#import "KVOObserver.h"
//加入头文件
#import <objc/message.h>

@interface KVOObserver ()
@property(nonatomic,copy)NSString *keyPath;
@property(nonatomic,copy)ObserverBlock block;
@property(nonatomic,__unsafe_unretained)id observedObject;

@end

@implementation KVOObserver

- (void)dealloc
{
    if(_observedObject) {
        [self stopObserving];
    }
    [super dealloc];
}

- (void)stopObserving
{
    [_observedObject removeObserver:self forKeyPath:_keyPath];
    _observedObject = nil;
    self.block = nil;
    self.keyPath = nil;
}


#pragma mark -- Block

+ (id)observerForObject:(id)object
                keyPath:(NSString *)keyPath
                options:(NSKeyValueObservingOptions)options
            changeBlock:(ObserverBlock)block
{
    KVOObserver *observer = [[KVOObserver alloc]init];
    if(observer)
    {
        if(!object || !keyPath || !block)
        {
            //            抛出异常
            [NSException raise:NSInternalInconsistencyException format:@"Observation must have a valid object (%@), keyPath (%@) and block(%@)", object, keyPath, block];
            self = nil;
        } else
        {
            observer.observedObject = object;
            observer.keyPath = keyPath ;
            observer.block = block;
            
            [observer.observedObject addObserver:observer
                                      forKeyPath:observer.keyPath
                                         options:options
                                         context:NULL];
        }
    }
    return observer;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    (self.block)(change);
}

#pragma mark -- Selector

+ (id)observerForObject:(id)object
                keyPath:(NSString *)keyPath
                options:(NSKeyValueObservingOptions)options
                 target:(id)target
                 action:(SEL)action
{
    id observer = nil;
    
    __weak id wTarget = target;
    __weak id wObject = object;
    
    ObserverBlock block =  ^(NSDictionary *change) {
        id msgTarget = wTarget;
        if(msgTarget) {
            ((void(*)(id, SEL, id, NSString *, NSDictionary *))objc_msgSend)(msgTarget, action, wObject, keyPath, change);
        }
    };
    
    if(block) {
        observer = [KVOObserver observerForObject:object keyPath:keyPath options:options changeBlock:block];
    }
    
    return observer;
}
@end

应用举例:

@interface AppDelegate ()

@property (nonatomic,copy)NSString *propertyToObserve;

@end


@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.propertyToObserve = [NSString stringWithFormat:@"old"];
    AppDelegate* object = self;

    KVOObserver *observerBlock  = [KVOObserver observerForObject:object keyPath:@"propertyToObserve" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld changeBlock:^(NSDictionary *change) {
        
        NSLog(@"propertyToObserve changed old:%@--new:%@",change[NSKeyValueChangeOldKey],change[NSKeyValueChangeNewKey]);
    }];

     KVOObserver *observerSelector = [KVOObserver observerForObject:object keyPath:@"propertyToObserve" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld target:self action:@selector(targetActionCallbackForObject:keyPath:change:)];

 [self performSelector:@selector(changePropertyToObserveValue) withObject:nil afterDelay:5];
}

-(void)targetActionCallbackForObject:(id)object keyPath:(NSString*)keyPath  change:(NSDictionary*)change
{
    NSLog(@"change %@",change);

}

-(void)changePropertyToObserveValue
{
    self.propertyToObserve = [NSString stringWithFormat:@"new"];
}

结果:
2015-01-21 19:00:10.701 Production[9112:935290] propertyToObserve changed old:(null)--new:old
2015-01-21 19:00:10.702 Production[9112:935290] change {
    kind = 1;
    new = old;
}
2015-01-21 19:00:15.704 Production[9112:935290] change {
    kind = 1;
    new = new;
    old = old;
}
2015-01-21 19:00:15.704 Production[9112:935290] propertyToObserve changed old:old--new:new


参考:

http://joeyio.com/2013/10/21/lightweight_kvo/

https://github.com/th-in-gs/THObserversAndBinders


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值