UI一揽子计划 17 (image的异步加载、KVO观察者模式、KVO进行豆瓣列表界面图片的异步加载)


把下载图片的封装起来   
ImageDownloader.h
#import <Foundation/Foundation.h>
@protocol ImageDownloaderDelegate <NSObject>
// 成功 把data 传递出去
- (void)imageDonwloadSuccessedWithData:(NSData *)data;
- (void)imageDonwloadFailedWithError:(NSError *)error;

// 失败 把失败原因传递出去

@end
@interface ImageDownloader : NSObject

// 写一个代理的属性
@property (nonatomic,assign)id<ImageDownloaderDelegate> delegate;


// 声明初始化方法
- (instancetype)initWithImageURL:(NSString *)imageUrl delegate:(id<ImageDownloaderDelegate>)delegate;

// 定义成外部类
- (void)start;
- (void)cancel;
@end
ImageDownloader .m
#import "ImageDownloader.h"
// 没有延展 自己写

@interface ImageDownloader ()<NSURLConnectionDelegate,NSURLConnectionDataDelegate>
@property (nonatomic,retain)NSMutableData *data;
@property (nonatomic,retain)NSURLConnection *connection;
@end



@implementation ImageDownloader

- (void)dealloc
{
    // 销毁/终止请求 最好写在控制器里
   // [self cancel];
    [_connection release];
    [_data release];
    [super dealloc];
}


- (instancetype)initWithImageURL:(NSString *)imageUrl delegate:(id<ImageDownloaderDelegate>)delegate
{
    self = [super init];
    if (self) {
        // 进行初始化  图片的请求
        NSURL *imageURL = [NSURL URLWithString:imageUrl];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:imageURL cachePolicy:(NSURLRequestUseProtocolCachePolicy) timeoutInterval:30];
        request.HTTPMethod = @"GET";
        self.delegate = delegate;
        // 请求创建一个链接
        // 使用代理方法
        self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
        // 开启
       
        // 最好是本类的对象 控制  增加灵活性
        [self start];
     //   [self.connection start];
    }
    return  self;
}

// 接受到服务器的信息 说明链接成功了 开始初始化
// 开始
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    self.data = [NSMutableData data];
}
// 中
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.data appendData:data];
    NSLog(@"加载中...");
}
// 结束
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // 使用代理  把data  传给控制器(因为 imageView 在控制器里创建的)
    // 代理不为空  并且代理实现了协议中的方法
    if (_delegate != nil && [_delegate respondsToSelector:@selector(imageDonwloadSuccessedWithData:)]) {
         [_delegate imageDonwloadSuccessedWithData:self.data];
    }
}
// 报错
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    if (_delegate != nil && [_delegate respondsToSelector:@selector(imageDonwloadFailedWithError:)]) {
        [_delegate imageDonwloadFailedWithError:error];
    }   
}
- (void)start
{
    [self.connection start];
}
- (void)cancel
{
    [self.connection cancel];
}
@end

KVO 键值观察者,是观察者设计模式的一种具体实现

KVO触发机制:一个对象(观察者),监测另一个对象(被观察者)的某属性是否发生变化,或被监测的属性发生更改,会触发观察者的一个方法(方法名固定好,类似代理方法)

KVO使用步骤:

1.注册观察者(为被观察者制定观察以及被观察属性)

addObserver添加一个观察者,forKeyPath被观察者的某个属性,options观察的变化,新的和老的,context上下文,可以是nil也可以携带参数.

[self.pangWeiSuo addObserver:self forKeyPath:@"hobby" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];

 

2.实现回调方法

其中KeyPath是观察的属性,object为被观察的对象,change为一个字典有new(新值)old(旧值),context为穿过来的值

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

{

      // 移除观察者

    [object removeObserver:self forKeyPath:@"hobby"];

    

}

 

3.触发回调方法(被观察属性发生更改)

self.pangWeiSuo.hobby = @"胖又猥琐";

 

4.移除观察者

 

KVO使用场景:MAC中M与C通信,M发生变化通知C.其中M是被观察者,C是观察者

KVO注意事项:观察者销毁之前,移除观察者,否则会出现程序异常(给以及销毁的对象发送消息)

 

KVO监测Model图片下载

1.在model中声明需要用到的属性

// 声明一个连接,来保存连接图片

@property (nonatomic, retain) UIImage *getUrlImage;

// 图片加载的状态

@property (nonatomic, assign) BOOL isDownLoading;

// 把加载图片的类声明成属性

@property (nonatomic, retain)ImageDownLoader*imageDownLoad;

- (void)imageDownLoader;

 

2.遵循ImageDownloaderDelegate的协议,实现协议中的两个方法

- (void)imageDownSucceedWithDate:(NSData *)data

{

    // model里的图片赋值,

    self.getUrlImage = [UIImage imageWithData:data];

    // 加载完毕修改状态

    self.isDownLoading = NO;

}

 

-(void)imageDownFailedWithDate:(NSError *)error

{

    // 标识加载失败

    self.isDownLoading = NO;

    NSLog(@"%@", error);

}

 

3.在model中添加一个开始的方法用于调用

 

- (void)imageDownLoader

{

 

    self.imageDownLoad = [[ImageDownLoader alloc] initWithImageURL:self.image delegate:self];

    [self.imageDownLoad start];

    // 标识正在加载

    self.isDownLoading = YES;

    

}

4.在dealloc 释放

- (void)dealloc

{

    [_imageDownLoad cancel];

}

 

5.在controller的设置cell的方法中,给model添加观察者

 

ActivityModel *model = self.dataArray[indexPath.row];

    

    // model添加观察者

    // 需要观察的是图片空的和未加载完成的时候

    if (model.getUrlImage == nil && model.isDownLoading == NO){

    // 添加观察者

      [model addObserver:self forKeyPath:@"getUrlImage" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:indexPath];

        [model imageDownLoader];

        // 添加一个占位符

        cell.activityImageView.image = [UIImage imageNamed:@"picholder"];

 

    } else {

        // 证明已经有图片了,把图片给cell 

        cell.activityImageView.image = model.getUrlImage;

    }

 

6.在观察者触发的方法中把model中的图片赋值为cell

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

{

    // 取出model对应的cell 

    NSIndexPath *indexPath = (NSIndexPath *)context;

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

    

    cell.activityImageView.image = change[@"new"];

    // 移除观察者


    [object removeObserver: self forKeyPath:keyPath];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值