TableView_图片异步加载 KVO

TableView 异步下载图片

ImageDownloader.h

#pragma mark - 声明block

//1,声明block

typedef void(^Result) (UIImage *img);

@interface ImageDownloaderViewController : UIViewController

#pragma mark - 声明方法

//block 做参数

//ImageDownloader 允许外界指定URL,提供 开始下载 和 取消下载 功能,并提供delegate或block将图⽚片传递给外界。

+ (void)imageDownloaderWithUrlStr:(NSString *)urlStr result:(Result)result;

 

ImageDownloader.m

 

+ (void)imageDownloaderWithUrlStr:(NSString *)urlStr result:( Result)result

{

    NSURL *url = [NSURL URLWithString:urlStr];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue new]autorelease] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        //把请求的二进制数据 转成图片

        UIImage *image = [UIImage imageWithData:data];

        //回到主线程调用

        dispatch_sync(dispatch_get_main_queue(), ^{

            //调用block 

            result(image);

        });

    }];

}

TableViewController.m

 

//加载数据

- (void)loadDataAndShow

{

    NSURL *url = [NSURL URLWithString:URL_NEW];

    

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    

    [request setHTTPMethod:@"GET"];

    __block NewsTableViewController *weakSelf = self;

        NSOperationQueue *queue = [[NSOperationQueue new] autorelease];

    //建立连接,

    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];

         //取大字典数据

        //从key为result的数组中 取字典

        //在此循环完成 即图片赋值完成

        for (NSDictionary *dic in dict[@"result"]) {

            //创建模型

            News *new = [News new];

           

            NSLog(@"模型创建,图片 开始下载");

            //此时 图片开始下载

            [new setValuesForKeysWithDictionary:dic];

            

            [weakSelf.allDataMutableArray addObject:new];

            [new release];

        }

        

        //回主线程

        dispatch_sync(dispatch_get_main_queue(), ^{

            //先刷新UI再拿到图片

            [weakSelf.tableView reloadData];

            NSLog(@" 刷新UI");

        });

    }];

}

 

 

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

#warning Incomplete method implementation.

    // Return the number of rows in the section.

    return _allDataMutableArray.count;

}

//显示Cell

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    NSLog(@"  显示 一个 cell");

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"new" forIndexPath:indexPath];

        // Configure the cell...

    News *new = _allDataMutableArray[indexPath.row];

        cell.textLabel.text = new.movieName;

    cell.detailTextLabel.text = new.movieId;

    //如果图片数据请求下来,就赋值显示。如果没有,就监听

    if (new.imageData != nil) {

        cell.imageView.image = new.imageData;

    }else{

             NSLog(@" 图片没请求下来---》》》监听 ");

        //KVO (1,注册监听)设置监听图片数据

        //new 被监听

        //self  监听者

        //keypath  监听属性

        //options   监听旧值 还是 新值

        //控制器 观察 -》模型(在控制器中观察)

        [new addObserver:self forKeyPath:@"imageData" options:NSKeyValueObservingOptionNew context:indexPath];

        }

    return cell;

}

 

#pragma mark - (2,实现回调方法)  KVO 监听被执行的方法,对象属性变化,即调用

//tableView 通过KVO观察 下载数据 及时更新页面

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{

    //判断标志

    if ([keyPath isEqualToString:@"imageData"]) {

        //1, 获取新图片数据

        UIImage *newImageData = change[NSKeyValueChangeNewKey];

        

        //2, 获取cell

        NSIndexPath *indexPath = (NSIndexPath *)context;

        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

        cell.imageView.image = newImageData;

        //3, 刷新当前行

        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];

        //4,取消监听

        [object removeObserver:self forKeyPath:keyPath];

        

         NSLog(@"(监听值变化)拿到图片了。。。。。。");

    }

}

//模型.h

@interface News : NSObject

@property(nonatomic,copy)NSString *movieId;

@property(nonatomic,copy)NSString *movieName;

@property(nonatomic,copy)NSString *pic_url;

//Model类注意事项:

//1、除了包含必要的数据外,还要包含⼀一个ImageDownloader对象。

//2、包含⼀一个image。

//3、包含⼀一个图⽚片是否正在下载的BOOL值。(⽤用于判断是否需要开始 下载)

@property(nonatomic,retain) UIImage *imageData;

 

//模型.m

 

#pragma mark - 重写pic_url 的 setter

//为了能正确显示图片,Model类应该提供图片获取功能(Model通过 ImageDownloader下载图片,供cell使用)

- (void)setPic_url:(NSString *)pic_url

{

    if (_pic_url != pic_url) {

        [_pic_url release];

        _pic_url = [pic_url retain];

        

        //

        //使用block 异步加载图片

        __block News *weakNews = self;

        [ImageDownloaderViewController imageDownloaderWithUrlStr:self.pic_url result:^(UIImage *img) {

            //将block 显示到imageView上

            //在这使用,就在这实现(模型中实现block)

            weakNews.imageData = img;

            NSLog(@"--------------拿到图片,赋值显示 NEws");

        }];

    }

}

 

原文地址:https://www.cnblogs.com/iOS-mt/p/4180812.html