第二十二章 Cocoa的大招: 键值编码和观察(KVO)

KVO,简介

所谓KVO,其实就是在KVC的基础上,再来个观察者模式。有关KVC的内容,请查看:第十四章 REST解惑——初识KVC


下面的范例我描述的不太清楚,各位在本文的末尾下载Demo,来看看

范例:根据时间的改变,更改tableviewcell的值

1.Table中,我们是这样设置的,正常的创建cell,然后给cell的相关属性赋值,

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"KVCTableViewCell";
    
    KVTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    if (cell==nil) {
        //创建cell
        cell = [[KVTableViewCell alloc] initWithReuseIdentifier:CellIdentifier];
        
        //设置cell的观察对象
        [cell setProperty:@"now"];
        [cell setObject:self];
    }
    
    return cell;
    
}


2.既然要根据时间来改变,那么在tableviewcontroll中,我们还得设置下时间

//设置一个每秒触发一次的事件
+ (RNTimer *)repeatingTimerWithTimerInterval:(NSTimeInterval)seconds block:(void (^)(void))block
{
    NSParameterAssert(seconds);
    NSParameterAssert(block);
    
    RNTimer *timer = [[self alloc] init];
    timer.block = block;
    timer.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    
    uint64_t nsec = (uint64_t)(seconds*NSEC_PER_SEC);
    
    dispatch_source_set_timer(timer.source, dispatch_time(DISPATCH_TIME_NOW, nsec), nsec, 0);
    
    dispatch_source_set_event_handler(timer.source, block);
    
    dispatch_resume(timer.source);
    
    return timer;
}

- (void)updateNow
{
    //更新时间
    self.now = [NSDate date];
}

- (void)viewDidLoad
{
    [self updateNow];
    
    __weak id weakSelf = self;
    
    //timer,每隔1秒,做更新时间的操作
    self.timer = [RNTimer repeatingTimerWithTimerInterval:1 block:^{
        [weakSelf updateNow];
    }];
}


3.但是,既然是要根据时间,来自动改变cell的text,那么,我们需要给cell添加个观察者,来观察自己的属性(从上面看到,它的属性为tableviewcontroll)是否发生了改变

//
//  KVTableViewCell.m
//  KVO_Demo
//
//  Created by Eric on 14-1-15.
//  Copyright (c) 2014年 Eric. All rights reserved.
//

#import "KVTableViewCell.h"

@implementation KVTableViewCell

//判断是否为空
- (BOOL)isReady
{
    return (self.object&&[self.property length]>0);
}

//更新时间
- (void)update
{
    self.textLabel.text = self.isReady?[[self.object valueForKey:self.property] description]:@"";
}

- (id)initWithReuseIdentifier:(NSString *)identifier
{
    return [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}

//移除观察者
- (void)removeObservation
{
    if (self.isReady) {
        [self.object removeObserver:self forKeyPath:self.property];
    }
}
//添加观察者
- (void)addObservation
{
    if ([self isReady]) {
        [self.object addObserver:self
                     forKeyPath:self.property
                         options:0
                         context:(__bridge void*)self];
    }
}

//当观察者发现 所观察的东西发生改变时 触发
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    //判断是否是我所观察的那个对象
    if ((__bridge id)context==self) {
        [self update];
    }else
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)dealloc
{
    if (_object &&[_property length]>0) {
        [_object removeObserver:self forKeyPath:_property];
    }
}

//当set属性的时候,便添加到观察者中
- (void)setObject:(id)anObject
{
    [self removeObservation];
    _object = anObject;
    [self addObservation];
    [self update];
}

//当set属性的时候,便添加到观察者中
- (void)setProperty:(NSString *)aProperty
{
    [self removeObservation];
    _property =aProperty;
    [self addObservation];
    [self update];
}

@end


Demo下载地址:KVO_Demo.zip

你可能感兴趣的:(KVO)