在这个Demo里面写了四个类:一个控制器类、一个操控数据类(即整理数据)、一个下载数据类、一个model类
在这里我用的数据路径是:
http://open.qyer.com/qyer/recommands/index?app_installtime=1427248095&client_id=qyer_ios&client_secret=cd254439208ab658ddf9&count=20&lat=40.02921998351221&lon=116.33752653006&page=1&track_app_channel=App%2520Store&track_app_version=6.1&track_device_info=iPhone%25204S&track_deviceid=47A7918C-4978-4091-B876-D0A2AE43AABB&track_os=ios%25207.1.2&v=1
//
// AppDelegate.m
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import "AppDelegate.h"
#import "RootViewController.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
RootViewController *rootVC = [[RootViewController alloc] init];
self.window.rootViewController = rootVC;
[rootVC release];
return YES;
}
控制器类:
//
// RootViewController.h
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface RootViewController :UIViewController
@end
//
// RootViewController.m
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import "RootViewController.h"
#import "ItemHandle.h"
#import "ItemModel.h"
@interface RootViewController ()<UITableViewDataSource,UITableViewDelegate,ItemHandleDelegate>
@property (nonatomic ,retain)UITableView *tableView;
//准备一个网络请求类的对象
@property (nonatomic ,retain)ItemHandle *itemHandle;
//tableView准备一个数组接收数据源
@property (nonatomic ,retain)NSMutableArray *dataArray;
@end
@implementation RootViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view.
self.tableView = [[UITableViewalloc] initWithFrame:self.view.frame];
self.tableView.backgroundColor = [UIColorbrownColor];
[self.viewaddSubview:self.tableView];
//给tableView设置代理
self.tableView.dataSource =self;
self.tableView.delegate =self;
[self.tableViewrelease];
//调用网络请求类itemHandle让该类去做网络请求 而自己只等着代理方法的回调拿到数据就行
self.itemHandle = [ItemHandleitemHandleWithUrlString:@"http://open.qyer.com/qyer/recommands/index?app_installtime=1427248095&client_id=qyer_ios&client_secret=cd254439208ab658ddf9&count=20&lat=40.02921998351221&lon=116.33752653006&page=1&track_app_channel=App%2520Store&track_app_version=6.1&track_device_info=iPhone%25204S&track_deviceid=47A7918C-4978-4091-B876-D0A2AE43AABB&track_os=ios%25207.1.2&v=1"andDelegate:self];
//开始启动网络连接
[self.itemHandlestartDownloader];
}
#pragma mark - 网络请求类的代理的方法
- (void)itemHandle:(ItemHandle *)handle didFinishLoadingItems:(NSMutableArray *)itemsArray
{
//一旦达到所有的model就要刷新界面
self.dataArray = itemsArray;
[self.tableViewreloadData];
}
#pragma mark -实现有协议方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID =@"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [[UITableViewCellalloc ] initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:cellID];
}
// cell.textLabel.text = @"测试数据";
//取出model
ItemModel *model = self.dataArray[indexPath.row];
//cell显示数据
cell.textLabel.text = model.title;
cell.textLabel.numberOfLines =0;
// cell.detailTextLabel.text = ;
if (model.picImage ==nil) {
//1下载之前先显示一张默认的图片下载完成之后再来更新该cell
cell.imageView.image = [UIImageimageNamed:@"6"];
//2给model的picImage属性添加观察者一旦该属性拿到新的图片就触发观察者方法
[model addObserver:selfforKeyPath:@"picImage"options:NSKeyValueObservingOptionNewcontext:indexPath];
//3开始下载图片
[modelloadItemImage];
}else {
//直接显示
cell.imageView.image = model.picImage;
}
return cell;
}
#pragma mark - 观察者的方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
//baindexpath传进来的主要原因
//下载完成之后检查该indexPath是否属于正在显示的cell
//如果是就刷新cell.imageView
//如果不是什么也不做 重用cell时候会根性给 indexPath
//context indexPath
//object 监听者对象model
//change 包含了新下载的image对象
//先拿到indexPath
NSIndexPath *indexPath = (NSIndexPath *)context;
//拿到iimage对象
UIImage *image = change[@"new"];
//拿到当前界面所有显示的cell的indexPath
NSArray *indexPathsArray = [self.tableViewindexPathsForVisibleRows];
//判断要更新的cell的indexpath是否在显示列表里面
if ([indexPathsArray containsObject:indexPath]) {
//取出该cell
// UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:indexPath];
UITableViewCell *cell = [self.tableViewcellForRowAtIndexPath:indexPath];
cell.imageView.image = image;
}
//移出监听者
[object removeObserver:selfforKeyPath:@"picImage"context:indexPath];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 120;
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)dealloc
{
[_dataArray release];
[_itemHandle release];
[_tableView release];
[superdealloc];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
操控数据类:
//
// ItemHandle.h
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import <Foundation/Foundation.h>
//协议 告诉代理对象 items 已经下载好让代理拿着用
@class ItemHandle;
@protocol ItemHandleDelegate <NSObject>
-(void)itemHandle:(ItemHandle *)handle didFinishLoadingItems:(NSMutableArray *)itemsArray;
@end
//用来操作数据的类
@interface ItemHandle :NSObject
//准备一个代理棒棒
@property (nonatomic ,assign)id<ItemHandleDelegate>delegate;
//准备一个urlString
@property (nonatomic ,retain)NSString *urlString;
//声明便利构造器
+ (ItemHandle *)itemHandleWithUrlString:(NSString *)urlString andDelegate:(id<ItemHandleDelegate>)delegate;
//开始请求数据的方法
- (void)startDownloader;
//quxia哦下载
- (void)cancelConnection;
@end
//
// ItemHandle.m
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import "ItemHandle.h"
#import "ItemModel.h"
@interface ItemHandle()<NSURLConnectionDataDelegate>
//创建连接对象
@property (nonatomic ,retain)NSURLConnection *connection;
//准备数据
@property (nonatomic ,retain)NSMutableData *allData;
@end
@implementation ItemHandle
#pragma mark - 自己为遍历构造器准备一个带有地址和代理对象的初始化方法
- (instancetype)initWithUrlString:(NSString *)urlString andDelegate:(id<ItemHandleDelegate>)delegate
{
self = [superinit];
if (self) {
self.urlString = urlString;
self.delegate = delegate;
}
return self;
}
#pragma mark - 开始下载
- (void)startDownloader
{
//拿到URL地址
NSString *urlstring = [self.urlStringstringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//创建url对象
NSURL *url = [NSURLURLWithString:urlstring];
//创建请求对象
NSURLRequest *request = [[NSURLRequestalloc] initWithURL:url];
//创建连接
self.connection = [NSURLConnectionconnectionWithRequest:request delegate:self];
}
#pragma mark - 取消lian接方法
-(void)cancelConnection
{
[self.connectioncancel];
self.connection =nil;
}
#pragma mark - connection的代理
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"收到回应");
//初始化数据data
self.allData = [NSMutableDatadata];
//收到数据
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"收到数据");
[self.allDataappendData:data];
}
#pragma mark - 链接结束 请求完成
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"请求完成");
//解析数据
//准备一个数组封装model
NSMutableArray *modelArray = [NSMutableArrayarray];
//调用解析数据方法并将数据扔到数组里面
[selfparserJsonDataWithArray:modelArray];
//告诉代理对象 请求完成 数据可以使用
if (_delegate && [_delegaterespondsToSelector:@selector(itemHandle:didFinishLoadingItems:)]) {
//实现
[_delegateitemHandle:selfdidFinishLoadingItems:modelArray];
}
}
#pragma mark - 解析数据方法
- (void)parserJsonDataWithArray:(NSMutableArray *)modelArray
{
//data->string 数据嵌套类型: 字典-》字典-》数组-》字典
// NSString *dataString = [[NSString alloc] initWithData:self.allData encoding:NSUTF8StringEncoding];
// NSLog(@"%@",dataString);
//开始解析数据
NSDictionary *dic = [NSJSONSerializationJSONObjectWithData:self.allDataoptions:NSJSONReadingMutableContainerserror:nil];
// NSLog(@"%@",dic);
//去data字典
NSDictionary *dataDic = dic[@"data"];
//取数组discount
NSArray *dataArray = dataDic[@"discount"];
// NSLog(@"%@",dataArray);
//封装model
for (NSDictionary *miniDicin dataArray) {
ItemModel *model = [ItemModelitemModelWithDictionary:miniDic];
//把model撞到数组中去
[modelArrayaddObject:model];
}
}
+ (ItemHandle *)itemHandleWithUrlString:(NSString *)urlString andDelegate:(id<ItemHandleDelegate>)delegate
{
ItemHandle *itemHandle = [[ItemHandlealloc] initWithUrlString:urlStringandDelegate:delegate];
//有对象之后就开始请求数据(因为已经有了URL数据)
return [itemHandle autorelease];
}
- (void)dealloc
{
[_connection release];
[_allDatarelease];
_delegate = nil;
[_urlString release];
[superdealloc];
}
@end
下载数据类:
//
// ImageDownLoader.h
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class ImageDownLoader;
@protocol imageDownLoaderDelegate <NSObject>
//下载成功的代理方法
- (void)imageDownLoader:(ImageDownLoader *)imageDownLoader downLoadSuccessWithImage:(UIImage *)image;
//下载失败的代理方法
- (void)imageDownLoader:(ImageDownLoader *)imageDownLoader failedWithError:(NSError *)error;
@end
@interface ImageDownLoader :NSObject
//代理棒棒
@property (nonatomic ,assign)id<imageDownLoaderDelegate>delegate;
//下载地址
@property (nonatomic ,retain)NSString *urlString;
- (instancetype)initWithUrlString:(NSString *)urlString andDelegate:(id<imageDownLoaderDelegate>)delegate;
//开始下载
-(void)startDownLoader;
//取消下载
- (void)cancelDownLoader;
@end
//
// ImageDownLoader.m
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import "ImageDownLoader.h"
@interface ImageDownLoader ()<NSURLConnectionDataDelegate>
@property (nonatomic ,retain)NSMutableData *allData;
@property (nonatomic ,retain)NSURLConnection *connection;
@end
@implementation ImageDownLoader
#pragma mark - 实现NSURLConnectionDataDelegate协议方法
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(@"收到响应");
self.allData = [NSMutableDatadata];
}
#pragma mark - 链接成功 接收数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"链接接收数据 图片下载");
[self.allDataappendData:data];
}
#pragma mark - 链接结束
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"图片下载结束");
//两件事
//1、把该图片数据缓存下次就不用下载
NSString *documentPath = [self getPath];
//拿到图片的name
NSString *imageName = [self.urlString stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
//图片的整个换粗你路径
NSString *filePath = [documentPath stringByAppendingPathComponent:imageName];
//缓存到文件中
[self.allData writeToFile:filePath atomically:YES];
//2、告诉代理拿到图片
//图片对象
UIImage *image = [UIImage imageWithData:self.allData];
if (_delegate && [_delegate respondsToSelector:@selector(imageDownLoader:downLoadSuccessWithImage:)]) {
[_delegate imageDownLoader:self downLoadSuccessWithImage:image];
}
}
#pragma mark - 链接失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"出错");
//告诉代理请求失败
//先判断代理是否存在再告诉代理请求失败
if (_delegate && [_delegate respondsToSelector:@selector(imageDownLoader:failedWithError:)]) {
[_delegate imageDownLoader:self failedWithError:error];
}
}
#pragma mark - 初始化
- (instancetype)initWithUrlString:(NSString *)urlString andDelegate:(id<imageDownLoaderDelegate>)delegate
{
self = [super init];
if (self) {
self.urlString = urlString ;
self.delegate = delegate;
}
[self startDownLoader];
return self;
}
#pragma mark - 开始下载方法
- (void)startDownLoader
{
if (self.urlString.length ==0) {
NSLog(@"地址都是错的,不能下载图片");
}else {
//正在下载图片之前先去缓存里面看看是否有该图片
//如果没有就下载,如果有就直接拿来并告诉代理拿到图片
NSLog(@"开始下砸");
//获得图片name
NSString *imageName = [self.urlString stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
//获得文件地址
NSString *filePath = [[self getPath] stringByAppendingPathComponent:imageName];
//创建文件管理器
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:filePath]) {
//如果有缓存不用 下载 直接告诉代理对象拿到图片
if (_delegate && [_delegate respondsToSelector:@selector(imageDownLoader:downLoadSuccessWithImage:)]) {
//创建image对象
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
//把image对象传给代理
[_delegate imageDownLoader:self downLoadSuccessWithImage:image];
}
}else {
//缓存中没有该图片那就开始下载
NSLog(@"开始下载图片");
//创建url对象
NSURL *url = [NSURL URLWithString:self.urlString];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
//开始链接获取数据
//先取消之前的链接
[self cancelDownLoader];
self.connection = [NSURLConnectionconnectionWithRequest:request delegate:self];
}
}
}
#pragma mark - 获取路径的方法
- (NSString *)getPath
{
NSString *path =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES).firstObject;
return path;
}
#pragma mark - 取消链接的方法
- (void)cancelDownLoader
{
[self.connectioncancel];
self.connection =nil;
}
- (void)dealloc
{
[_allDatarelease];
[_connection release];
[_urlString release];
_delegate = nil;
[superdealloc];
}
@end
model类:
//
// ItemModel.h
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface ItemModel :NSObject
@property (nonatomic ,retain)NSString *end_date;
@property (nonatomic ,retain)NSString *idd;
@property (nonatomic ,retain)NSString *photo;
@property (nonatomic ,retain)NSString *price;
@property (nonatomic ,retain)NSString *priceoff;
@property (nonatomic ,retain)NSString *title;
@property (nonatomic ,retain)UIImage *picImage;
//用字典给model赋值
+ (ItemModel *)itemModelWithDictionary:(NSDictionary *)infoDic;
//下载图片的方法
- (void)loadItemImage;
@end
//
// ItemModel.m
// KVODemo
//
// Created by lanouhn on 15-8-18.
// Copyright (c) 2015年 尹江涛-lesson16-8.18. All rights reserved.
//
#import "ItemModel.h"
#import "ImageDownLoader.h"
@interface ItemModel ()<imageDownLoaderDelegate>
@end
@implementation ItemModel
#pragma mark - 初始化
- (instancetype)initWithDic:(NSDictionary *)infoDic
{
self = [superinit];
if (self) {
//给model赋值
for (NSString *keyin infoDic) {
if ([key isEqualToString:@"end_date"]) {
self.end_date = infoDic[@"end_date"];
}else if([keyisEqualToString:@"id"]) {
self.idd = infoDic[@"id"];
}else if ([keyisEqualToString:@"price"]){
self.price = infoDic[@"price"];
}else if ([keyisEqualToString:@"priceoff"]){
self.priceoff = infoDic[@"priceoff"];
}else if ([keyisEqualToString:@"title"]){
self.title = infoDic[@"title"];
}else if ([keyisEqualToString:@"photo"]){
//首先给属性赋值
self.photo = infoDic[@"photo"];
//得到imageName
//将字符串的/替换成_
NSString *imageName = [self.photostringByReplacingOccurrencesOfString:@"/"withString:@"_"];
//获得要缓存的路径
NSString *filePath = [[selfgetPath] stringByAppendingPathComponent:imageName];
//创建文件夹管理对象
NSFileManager *fileManager = [NSFileManagerdefaultManager];
//判断路径下面有没有该缓存的文件
//路径是否存在
if ([fileManager fileExistsAtPath:filePath]) {
//如果存在直接拿出用
self.picImage = [UIImageimageWithContentsOfFile:filePath];
}else {
//没有该缓存图片 去下载该图片
//model不管 谁用谁去下载
}
}
}
}
return self;
}
#pragma mark - imageDownLoader代理方法
- (void)imageDownLoader:(ImageDownLoader *)imageDownLoader downLoadSuccessWithImage:(UIImage *)image
{
self.picImage = image;
}
#pragma mark - 下载失败
- (void)imageDownLoader:(ImageDownLoader *)imageDownLoader failedWithError:(NSError *)error
{
NSLog(@"%@",[errorlocalizedDescription]);
}
#pragma mark - 获得缓存路径的方法
- (NSString *)getPath
{
//获得应用程序文件路径
NSString *path =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES ).firstObject;
return path;
}
#pragma mark - 用字典给model赋值
+ (ItemModel *)itemModelWithDictionary:(NSDictionary *)infoDic
{
ItemModel *model = [[ItemModelalloc] initWithDic:infoDic];
return [model autorelease];
}
#pragma mark - xiazai下载图片的方法
- (void)loadItemImage
{
//调用图片下载类去下载图片
[[ImageDownLoaderalloc] initWithUrlString:self.photoandDelegate:self];
}
- (void)dealloc
{
[_end_date release];
[_photorelease];
[_pricerelease];
[_priceoff release];
[_titlerelease];
[_iddrelease];
[_picImage release];
[superdealloc];
}
@end