首先封装异步下载,然后给加载的图片设置观察者。
说的简单,做起来有点难度,级别:⭐️⭐️
重点:
设置观察者的步骤
- 添加观察者,观察者是一个对象,被观察者是一个属性
- 实现观察者方法
- 移除观察者
获取网络数据的步骤
- 网址对象
NSURL *url = [NSURL URLWithString:kActivityListURL]; - 创建请求对象
NSURLRequest * request = [NSURLRequest requestWithURL:url]; - 连接对象
[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进行注册,当时应为没有注册,一致找不到错误