iOS KVO方式监听数组变化方法

iOS默认不支持对数组的KVO,因为普通方式监听的对象的地址的变化,而数组地址不变,而是里面的值发生了改变

整个过程需要三个步骤 (与普通监听一致)

/*

*  第一步 建立观察者及观察的对象

*  第二步 处理key的变化(根据key的变化刷新UI)

*  第三步 移除观察者

*/

[objc] view plain copy
数组不能放在UIViewController里面,在这里面的数组是监听不到数组大小的变化的,需要将需要监听的数组封装到model里面<

model类为: 将监听的数组封装到model里,不能监听UIViewController里面的数组

两个属性 一个 字符串类的姓名,一个数组类的modelArray,我们需要的就是监听modelArray里面元素的变化

[objc] view plain copy
@interface model : NSObject
@property(nonatomic, copy)NSString *name;
@property(nonatomic, retain)NSMutableArray *modelArray;

1 建立观察者及观察的对象
第一步 建立观察者及观察的对象

[_modeladdObserver:selfforKeyPath:@"modelArray"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOldcontext:NULL];

第二步 处理key的变化(根据key的变化刷新UI)

最重要的就是添加数据这里

[objc] view plain copy
不能这样 [_model.modelArray addObject]方法,需要这样调用 [[_model mutableArrayValueForKey:@"modelArray"] addObject:str];原因稍后说明。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

[objc] view plain copy
{
if ([keyPath isEqualToString:@"modelArray"]) {
[_tableView reloadData];
}
}

第三步 移除观察者

[objc] view plain copy
if (_model != nil) {
[_model removeObserver:self forKeyPath:@"modelArray"];
}

以下附上本文代码:
代码中涉及三点

1 根据数组动态刷新tableview;

2 定时器的使用(涉及循环引用问题);

3 使用KVC优化model的初始化代码。

没找到上传整个工程的方法,暂时附上代码

1 NSTimer相关

[objc] view plain copy
//
// 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

[objc] view plain copy
//
// 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

2 model相关
[objc] view plain copy

//  
//  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  

[objc] view plain copy
//
// model.m
// KVOTableview
//
//

//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  

3 UIViewController相关

//  
//  RootViewController.m  
//  KVOTableview  
  
/* 
    *  第一步 建立观察者及观察的对象 
    *  第二步 处理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:(voidvoid *)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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 【原】iOS下KVO使用过程中的陷阱KVO,全称为Key-Value Observing,是iOS中的一种设计模式...
    nadou23阅读 1,958评论 0 0
  • 1.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令伟阅读 1,049评论 0 10
  • 把网上的一些结合自己面试时遇到的面试题总结了一下,以后有新的还会再加进来。 1. OC 的理解与特性 OC 作为一...
    AlaricMurray阅读 2,560评论 0 20
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,703评论 0 9
  • 看压缩包中的README.md 在Setting-User中覆盖Setting-Default的配置,可以自己定义...
    吴世浩阅读 472评论 0 1