一、實現一個簡單的tableView顯示效果
實現效果展示:
程式碼範例(使用以前在主控制器中進行業務處理的方式)
1.建立一個項目,讓控制器繼承自UITableViewController。
複製代碼 代碼如下:
//
// YYViewController.h
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface YYViewController : UITableViewController
@end
2.處理storyboard中得介面,如下:
3.根據plist檔案,字典轉模型
建立一個類,繼承自NSObject,作為資料的模型
YYappModel.h檔案
複製代碼 代碼如下:
//
// YYappModel.h
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface YYappModel : NSObject
/**
*應用程式名稱
*/
@property(nonatomic,copy)NSString *name;
/**
* 應用圖片
*/
@property(nonatomic,copy)NSString *icon;
/**
* 應用的下載量
*/
@property(nonatomic,copy)NSString *download;
+(instancetype)appModelWithDict:(NSDictionary *)dict;
-(instancetype)initWithDict:(NSDictionary *)dict;
@end
YYappModel.m檔案
複製代碼 代碼如下:
//
// YYappModel.m
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYappModel.h"
@implementation YYappModel
-(instancetype)initWithDict:(NSDictionary *)dict
{
if (self=[super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
//Factory 方法
+(instancetype)appModelWithDict:(NSDictionary *)dict
{
return [[self alloc]initWithDict:dict];
}
@end
主控制器中得邏輯控制部分,YYViewController.m檔案
複製代碼 代碼如下:
//
// YYViewController.m
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
#import "YYappModel.h"
@interface YYViewController ()
@property(nonatomic,strong)NSArray *apps;
@end
複製代碼 代碼如下:
@implementation YYViewController
#pragma mark- 懶載入
-(NSArray *)apps
{
if (_apps==nil) {
NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
//字典轉模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
}
#pragma mark-資料來源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"ID";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
YYappModel *app=self.apps[indexPath.row];
cell.textLabel.text=app.name;
cell.detailTextLabel.text=app.download;
//下載圖片資料
NSLog(@"載入圖片資料---%@", [NSThread currentThread]);
NSURL *url=[NSURL URLWithString:app.icon];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *imgae=[UIImage imageWithData:data];
cell.imageView.image=imgae;
NSLog(@"完成顯示");
return cell;
}
@end
列印查看:
二、自訂NSOperation
說明:上面的下載圖片資料部分是一個非常耗時的操作,這個操作任務在主線程完成,會嚴重的影響到使用者體驗,造成UI卡的現象。下面通過自訂NSOperation,新開線程,讓載入圖片的任務非同步執行。
1.通過代理
在上面的基礎上,建立一個類,讓其繼承自NSOperation。
YYdownLoadOperation.h檔案
複製代碼 代碼如下:
//
// YYdownLoadOperation.h
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import <Foundation/Foundation.h>
#pragma mark-設定代理和代理方法
@class YYdownLoadOperation;
@protocol YYdownLoadOperationDelegate <NSObject>
-(void)downLoadOperation:(YYdownLoadOperation*)operation didFishedDownLoad:(UIImage *)image;
@end
複製代碼 代碼如下:
@interface YYdownLoadOperation : NSOperation
@property(nonatomic,copy)NSString *url;
@property(nonatomic,strong)NSIndexPath *indexPath;
@property(nonatomic,strong)id <YYdownLoadOperationDelegate> delegate;
@end
YYdownLoadOperation.m檔案
複製代碼 代碼如下:
//
// YYdownLoadOperation.m
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYdownLoadOperation.h"
@implementation YYdownLoadOperation
-(void)main
{
NSURL *url=[NSURL URLWithString:self.url];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *imgae=[UIImage imageWithData:data];
NSLog(@"--%@--",[NSThread currentThread]);
//圖片下載完畢後,通知代理
if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) {
dispatch_async(dispatch_get_main_queue(), ^{//回到主線程,傳遞資料給代理對象
[self.delegate downLoadOperation:self didFishedDownLoad:imgae];
});
}
}
@end
主控制器中的商務邏輯:
複製代碼 代碼如下:
//
// YYViewController.m
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
#import "YYappModel.h"
#import "YYdownLoadOperation.h"
@interface YYViewController ()<YYdownLoadOperationDelegate>
@property(nonatomic,strong)NSArray *apps;
@property(nonatomic,strong)NSOperationQueue *queue;
@end
複製代碼 代碼如下:
@implementation YYViewController
#pragma mark- 懶載入apps
-(NSArray *)apps
{
if (_apps==nil) {
NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
//字典轉模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
}
#pragma mark-懶載入queue
-(NSOperationQueue *)queue
{
if (_queue==Nil) {
_queue=[[NSOperationQueue alloc]init];
//設定最大並發數為3
_queue.maxConcurrentOperationCount=3;
}
return _queue;
}
#pragma mark-資料來源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"ID";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
YYappModel *app=self.apps[indexPath.row];
cell.textLabel.text=app.name;
cell.detailTextLabel.text=app.download;
//下載圖片資料
// NSLog(@"載入圖片資料---%@", [NSThread currentThread]);
// NSURL *url=[NSURL URLWithString:app.icon];
// NSData *data=[NSData dataWithContentsOfURL:url];
// UIImage *imgae=[UIImage imageWithData:data];
// cell.imageView.image=imgae;
//建立一個OPeration對象
YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init];
operation.url=app.icon;
operation.indexPath=indexPath;
operation.delegate=self;
//把操作對象添加到隊列中在去
[self.queue addOperation:operation];
// NSLog(@"完成顯示");
return cell;
}
-(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
{
//返回圖片資料給每行對應的cell的imageview.image
//取出tableview中indexPath這一行對應的cell
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:operation.indexPath];
//顯示圖片
cell.imageView.image=image;
// NSLog(@"cell--index--%@---%@",operation.indexPath,[NSThread currentThread]);
//一定要重新整理表格
[self.tableView reloadData];
NSLog(@"--%@--",[NSThread currentThread]);
}
@end
說明:通過列印可以發現上面的代碼存在很大的問題。
問題1:需要保證一個url對應一個operation對象。
問題2:下載完需要移除。移除執行完畢的操作。
問題3:保證一個url對應一個image。
下面對主控制器中得代碼進行改進:
複製代碼 代碼如下:
//
// YYViewController.m
// 01-自訂Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
//
#import "YYViewController.h"
#import "YYappModel.h"
#import "YYdownLoadOperation.h"
@interface YYViewController ()<YYdownLoadOperationDelegate>
@property(nonatomic,strong)NSArray *apps;
@property(nonatomic,strong)NSOperationQueue *queue;
@property(nonatomic,strong)NSMutableDictionary *operations;
@property(nonatomic,strong)NSMutableDictionary *images;
@end
複製代碼 代碼如下:
@implementation YYViewController
#pragma mark- 懶載入apps
-(NSArray *)apps
{
if (_apps==nil) {
NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
//字典轉模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
}
#pragma mark-懶載入queue
-(NSOperationQueue *)queue
{
if (_queue==Nil) {
_queue=[[NSOperationQueue alloc]init];
//設定最大並發數為3
_queue.maxConcurrentOperationCount=3;
}
return _queue;
}
#pragma mark-懶載入operations
-(NSMutableDictionary *)operations
{
if (_operations==Nil) {
_operations=[NSMutableDictionary dictionary];
}
return _operations;
}
#pragma mark-懶載入images
-(NSMutableDictionary *)images
{
if (_images==Nil) {
_images=[NSMutableDictionary dictionary];
}
return _images;
}
#pragma mark-資料來源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"ID";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
YYappModel *app=self.apps[indexPath.row];
cell.textLabel.text=app.name;
cell.detailTextLabel.text=app.download;
//保證一個url對應一個image對象
UIImage *image=self.images[app.icon];
if (image) {//緩衝中有圖片
cell.imageView.image=image;
}else // 緩衝中沒有圖片,得下載
{
//先設定一張佔位圖片
cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];
YYdownLoadOperation *operation=self.operations[app.icon];
if (operation) {//正在下載
//什麼都不做
}else //當前沒有下載,那就建立操作
{
operation=[[YYdownLoadOperation alloc]init];
operation.url=app.icon;
operation.indexPath=indexPath;
operation.delegate=self;
[self.queue addOperation:operation];//非同步下載
self.operations[app.icon]=operation;
}
}
return cell;
}
-(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
{
//1.移除執行完畢的操作
[self.operations removeObjectForKey:operation.url];
//2.將圖片放到緩衝中
self.images[operation.url]=image;
//3.重新整理表格(只重新整理下載的那一行)
[self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]);
}
@end
列印查看: