KVO 观察者设计模式 代码实现 常用
前提需要将之前编辑好的两个DownLoadTool文件拖过来
(DownLoadTool.h DownLoadTool.m)
TableViewController.m
#import "TableViewController.h"
#import "TableViewCell.h"
#import "Model.h"
#import "DownLoadTool.h"
@interface TableViewController ()
@property(nonatomic,strong)NSMutableArray * dataArray;
@end
@implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化数组
self.dataArray = [NSMutableArray array];
//请求数据
[DownLoadTool downLoadWithURL:@"http://project.lanou3g.com/teacher/yihuiyun/lanouproject/activitylist.php" method:@"GET" param:nil passValue:^(id value) {
//解析数据
NSDictionary * tempDict = [NSJSONSerialization JSONObjectWithData:value options:(NSJSONReadingAllowFragments) error:nil];
for (NSDictionary * dict in tempDict[@"events"]) {
Model * m = [[Model alloc]init];
[m setValuesForKeysWithDictionary:dict];
[self.dataArray addObject:m];
}
//更新数据
[self.tableView reloadData];
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete method implementation.
// Return the number of rows in the section.
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
//获取对应的model对象
Model * m = self.dataArray[indexPath.row];
//赋值
cell.lab.text = m.title;
//加载图片
if (m.loadImage == nil && m.isLoading == NO) {
//如果满足这个条件,说明图片可以显示
//这种情况就启用占位图
cell.imV.image = [UIImage imageNamed:@"000.png"];
//加载图片数据
[m downLoadImage];
//添加观察者
//__bridge_retained 桥接的作用将c语言转成OC
[m addObserver:self forKeyPath:@"loadImage" options:(NSKeyValueObservingOptionNew) context:(__bridge_retained void *)(indexPath)];
}else{
//加载中
//判断图片是否下载完成
if (m.image == nil) {
//如果未完成,使用占位符
cell.imV.image = [UIImage imageNamed:@"000.png"];
}else{
//完成 就是用下载后的图片
cell.imV.image = m.loadImage;
}
}
return cell;
}
//
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
// 1 拿到新值
UIImage * newImage = change[NSKeyValueChangeNewKey];
// 判空
if ([newImage isEqual:[NSNull null]]) {
return;
}
// 2 拿到当前显示的cell(index)
NSArray * indexArray = [self.tableView indexPathsForVisibleRows];
// 3 拿到刚请求到图片的cell的indexPath
// __bridge NSIndexPath *
NSIndexPath * indexPath = (__bridge NSIndexPath *)(context);
// 4 判断是否正在显示
if ([indexArray containsObject:indexPath]) {
// 拿到cell
TableViewCell * cell = (TableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
// 换图片
cell.imV.image = newImage;
}
// 移除观察者
[object removeObserver:self forKeyPath:@"loadImage"];
}
@end
TableViewCell.h
#import <UIKit/UIKit.h>
@interface TableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *lab;
@property (weak, nonatomic) IBOutlet UIImageView *imV;
@end
Model.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
@interface Model : NSObject
@property(nonatomic,copy)NSString * image;
@property(nonatomic,copy)NSString * title;
// 用来缓存图片
@property(nonatomic,strong)UIImage * loadImage;
// 判断图片是否正在加载
@property(nonatomic,assign)BOOL isLoading;
// 加载图片
-(void)downLoadImage;
@end
Model.m
#import "Model.h"
#import "DownLoadTool.h"
@implementation Model
-(void)downLoadImage{
[DownLoadTool downLoadWithURL:_image method:@"GET" param:nil passValue:^(id value) {
self.loadImage = [UIImage imageWithData:value];
//加载完成 (意味着不在加载中)
_isLoading = NO;
}];
// 加载中
_isLoading = YES;
}
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
}
@end