写作本文来由: iOS默认不支持对数组的KVO,因为普通方式监听的对象的地址的变化,而数组地址不变,而是里面的值发生了改变
整个过程需要三个步骤 (与普通监听一致)
/*
* 第一步 建立观察者及观察的对象
* 第二步 处理key的变化(根据key的变化刷新UI)
* 第三步 移除观察者
*/
数组不能放在UIViewController里面,在这里面的数组是监听不到数组大小的变化的,需要将需要监听的数组封装到model里面<
model类为: 将监听的数组封装到model里,不能监听UIViewController里面的数组
两个属性 一个 字符串类的姓名,一个数组类的modelArray,我们需要的就是监听modelArray里面元素的变化
@interface model : NSObject @property(nonatomic, copy)NSString *name; @property(nonatomic, retain)NSMutableArray *modelArray;
第一步 建立观察者及观察的对象
[_modeladdObserver:selfforKeyPath:@"modelArray"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:NULL];
第二步 处理key的变化(根据key的变化刷新UI)
最重要的就是添加数据这里
不能这样 [_model.modelArray addObject]方法,需要这样调用 [[_model mutableArrayValueForKey:@"modelArray"] addObject:str];原因稍后说明。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{ if ([keyPath isEqualToString:@"modelArray"]) { [_tableView reloadData]; } }
if (_model != nil) { [_model removeObserver:self forKeyPath:@"modelArray"]; }
代码中涉及三点
1 根据数组动态刷新tableview;
2 定时器的使用(涉及循环引用问题);
3 使用KVC优化model的初始化代码。
没找到上传整个工程的方法,暂时附上代码
1 NSTimer相关
// // NSTimer+DelegateSelf.h // KVOTableview // // Created by 程立彬 on 14-8-8. // Copyright (c) 2014年 chenglb. All rights reserved. // //为防止controller和nstimer之间的循环引用,delegate指向当前单例,而不指向controller #import <Foundation/Foundation.h> @interface NSTimer (DelegateSelf) +(NSTimer *)scheduledTimerWithTimeInterval:(int)timeInterval block:(void(^)())block repeats:(BOOL)yesOrNo; @end
// // NSTimer+DelegateSelf.m // KVOTableview // // Created by 程立彬 on 14-8-8. // Copyright (c) 2014年 chenglb. All rights reserved. // #import "NSTimer+DelegateSelf.h" @implementation NSTimer (DelegateSelf) +(NSTimer *)scheduledTimerWithTimeInterval:(int)timeInterval block:(void(^)())block repeats:(BOOL)yesOrNo { return [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:@selector(callBlock:) userInfo:[block copy] repeats:yesOrNo]; } +(void)callBlock:(NSTimer *)timer { void(^block)() = timer.userInfo; if (block != nil) { block(); } } @end
// // model.h // KVOTableview // // Created by 程立彬 on 14-8-8. // Copyright (c) 2014年 chenglb. All rights reserved. // #import <Foundation/Foundation.h> @interface model : NSObject @property(nonatomic, copy)NSString *name; @property(nonatomic, retain)NSMutableArray *modelArray; -(id)initWithDic:(NSDictionary *)dic; @end
// // model.m // KVOTableview // // Created by 程立彬 on 14-8-8. // Copyright (c) 2014年 chenglb. All rights reserved. // //KVC的应用 简化冗余代码 #import "model.h" @implementation model -(id)initWithDic:(NSDictionary *)dic { self = [super init]; if (self) { [self setValuesForKeysWithDictionary:dic]; } return self; } -(void)setValue:(id)value forUndefinedKey:(NSString *)key { NSLog(@"undefine key ---%@",key); } @end
// // RootViewController.m // KVOTableview // // Created by 程立彬 on 14-8-8. // Copyright (c) 2014年 chenglb. All rights reserved. // /* * 第一步 建立观察者及观察的对象 * 第二步 处理key的变化(根据key的变化刷新UI) * 第三步 移除观察者 */ #import "RootViewController.h" #import "NSTimer+DelegateSelf.h" #import "model.h" #define TimeInterval 3.0 @interface RootViewController ()<UITableViewDelegate,UITableViewDataSource> @property(nonatomic, retain)NSTimer *timer; @property(nonatomic, retain)UITableView *tableView; @property(nonatomic, retain)model *model; @end @implementation RootViewController - (void)dealloc { //第三步 if (_model != nil) { [_model removeObserver:self forKeyPath:@"modelArray"]; } //停止定时器 if (_timer != nil) { [_timer invalidate]; _timer = nil; } } - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { NSDictionary *dic = [NSDictionary dictionaryWithObject:[NSMutableArray arrayWithCapacity:0] forKey:@"modelArray"]; self.model = [[model alloc] initWithDic:dic]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; //第一步 [_model addObserver:self forKeyPath:@"modelArray" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL]; self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; _tableView.delegate = self; _tableView.dataSource = self; _tableView.backgroundColor = [UIColor lightGrayColor]; [self.view addSubview:_tableView]; //定时添加数据 [self startTimer]; } //添加定时器 -(void)startTimer { __block RootViewController *bself = self; _timer = [NSTimer scheduledTimerWithTimeInterval:TimeInterval block:^{ [bself changeArray]; } repeats:YES]; } //增加数组中的元素 自动刷新tableview -(void)changeArray { NSString *str = [NSString stringWithFormat:@"%d",arc4random()%100]; [[_model mutableArrayValueForKey:@"modelArray"] addObject:str]; } //第二步 处理变化 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"modelArray"]) { [_tableView reloadData]; } } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [_model.modelArray count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; { static NSString *cellidentifier = @"cellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellidentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellidentifier]; } cell.textLabel.text = _model.modelArray[indexPath.row]; return cell; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end