KVO和异步图片下载的结合使用

首先封装异步下载,然后给加载的图片设置观察者。
说的简单,做起来有点难度,级别:⭐️⭐️

重点:

设置观察者的步骤

  1. 添加观察者,观察者是一个对象,被观察者是一个属性
  2. 实现观察者方法
  3. 移除观察者

获取网络数据的步骤

  1. 网址对象
    NSURL *url = [NSURL URLWithString:kActivityListURL];
  2. 创建请求对象
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
  3. 连接对象
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {}];

封装到AsynImageDownLoader中


#import <Foundation/Foundation.h>
#import "AsynImageDownLoaderDelegate.h"



@interface AsynImageDownLoader : NSObject<NSURLConnectionDelegate,NSURLConnectionDataDelegate>

@property(nonatomic,assign)id <AsynImageDownLoaderDelegate> delegate;

@property(nonatomic,assign)BOOL isDownLoading;

-(instancetype)initWithImageUrl:(NSString *)imageUrl;

-(void)cancelRequest;//取消请求(为了防止多次重复提交);

@end

.m中的文件是


#import "AsynImageDownLoader.h"
#import <UIKit/UIKit.h>



//@protocol AsynImageDownLoaderDelegate <NSObject>
//
//-(void)AsynImageDowner
//
//@end

@interface AsynImageDownLoader ()
@property(nonatomic,retain)NSMutableData * receiveData;//接受每次传过来的数据

@property(nonatomic,retain)NSURLConnection * connection;


@end

@implementation AsynImageDownLoader


-(instancetype)initWithImageUrl:(NSString *)imageUrl
{
    self = [super init];
    if (self) {

    //网址对象

    NSURL *url = [NSURL URLWithString:imageUrl];

    //创建请求对象

    NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];

    //创建连接
    self.connection = [NSURLConnection connectionWithRequest:request delegate:self];

    }


    return self;

}

-(void)cancelRequest{

    [_connection cancel];

}


#pragma mark ----------------实现协议中的方法

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    self.receiveData = [NSMutableData data];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{

    //此方法中isDownLoading = YES;
    _isDownLoading = YES; //表示正在下载


    [_receiveData appendData:data];

    UIImage *image = [UIImage imageWithData:_receiveData];

    if ([_delegate respondsToSelector:@selector(AsynImageDownLoader:isLoading:)]) {

        [_delegate AsynImageDownLoader:self isLoading:image];
    }



}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    _isDownLoading = NO;//下载完毕
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{

}


@end

下载好得图片需要使用代理传值,所以定义一个协议AsynImageDownLoaderDelegate

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@class AsynImageDownLoader;

@protocol AsynImageDownLoaderDelegate <NSObject>

-(void)AsynImageDownLoader:(AsynImageDownLoader *)downLoader isLoading:(UIImage *)image;




@end

用Activity来接受

#import <Foundation/Foundation.h>
#import "AsynImageDownLoaderDelegate.h"
@interface Activity : NSObject<AsynImageDownLoaderDelegate>

@property(nonatomic,retain)NSString * image;//图片网址

@property(nonatomic,retain)NSString * title;//标题

@property(nonatomic,retain)UIImage * picture; //用来接受异步下载得到的图片

-(void)loadImage;//通过图片网址下载图片

@end

.m中的代码

#import "Activity.h"
#import "AsynImageDownLoader.h"

@implementation Activity

-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{



}


-(void)loadImage{

    AsynImageDownLoader *downLoader = [[AsynImageDownLoader alloc]initWithImageUrl:_image];

    //设置代理
    downLoader.delegate = self;

}

-(void)AsynImageDownLoader:(AsynImageDownLoader *)downLoader isLoading:(UIImage *)image
{

    self.picture = image;
}


- (void)dealloc
{
    [_image release];
    [_title release];
    [super dealloc];
}
@end

将图像显示到cell中,cell是重新定义的类。

最后是ActivityyTableViewController.h中的代码


#import <UIKit/UIKit.h>
#import "Activity.h"
#import "ActivityCell.h"

#define kActivityListURL @"http://project.lanou3g.com/teacher/yihuiyun/lanouproject/activitylist.php"

@interface ActivityyTableViewController : UITableViewController

@end

.m中的代码

#import "ActivityyTableViewController.h"


@interface ActivityyTableViewController ()

@property(nonatomic,retain)NSMutableArray * activityesArray;

@end

@implementation ActivityyTableViewController

- (void)dealloc
{
    [_activityesArray release];
    [super dealloc];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    //1.网址对象

    NSURL *url = [NSURL URLWithString:kActivityListURL];

    //2.创建请求对象

    NSURLRequest * request = [NSURLRequest requestWithURL:url];

    //3.连接对象


    __block ActivityyTableViewController *TVC = self;

#warning mark----------------给活动数组开辟空间
    TVC.activityesArray = [NSMutableArray array];

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

        if (data != nil) {
#pragma mark ------------------进行数据解析

            NSMutableDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error:nil];
            NSMutableArray *arr = [dic objectForKey:@"events"];

            for (NSDictionary *dict in arr) {

                Activity *activity = [[Activity alloc]init];

                //使用kvc赋值
                [activity setValuesForKeysWithDictionary:dict];

                [_activityesArray addObject:activity];
                [activity release];
            }

            //遍历数组,看看是否有值
            NSLog(@"%@",_activityesArray);
        }

        //刷新数据

        [TVC.tableView reloadData];


    }];


    // Uncomment the following line to preserve selection between presentations.
    // self.clearsSelectionOnViewWillAppear = NO;

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}

- (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 [_activityesArray count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    ActivityCell *cell = [tableView dequeueReusableCellWithIdentifier:@"activity" forIndexPath:indexPath];

    //设置cell上显示的内容
    //1.获取活动对象

    Activity *activity = _activityesArray[indexPath.row];

    cell.activity = activity;

    // 如果Activity

    if (activity.picture == nil) {

        [activity loadImage];

        //①添加观察者

        [activity addObserver:self forKeyPath:@"picture" options:NSKeyValueObservingOptionNew context:[indexPath retain]];
    }else{

        cell.ImageView.image = activity.picture;
    }

    return cell;
}

//②实现观察者方法

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    //1.1获取picture改变之后的值,既得到每次传过来的图片

    UIImage *image = [change objectForKey:@"new"];

    //1.2通过context(即indexPath)获取要显示图片的cell

    NSIndexPath * indexPath = (NSIndexPath *)context;

    //获取当前屏幕上正在显示的cell
    //此时数组中存放的是当前正在显示的cell的indePath
    NSArray * showArray = [self.tableView indexPathsForVisibleRows];

    //判断当前activity对象(或其picture)是否对应当前showArray中正在显示的cell
    if ([showArray containsObject:indexPath]) {
        //获取indexPath位置上的cell

        ActivityCell *cell = (ActivityCell *)[self.tableView cellForRowAtIndexPath:indexPath];

        cell.ImageView.image = image;
    }

    [indexPath release];

    //④移除观察者
    [object removeObserver:self forKeyPath:keyPath context:context];
}
@end

这里面一定要对cell进行注册,当时应为没有注册,一致找不到错误

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值