iOS多線程應(yīng)用開(kāi)發(fā)中自定義NSOperation類的實(shí)例解析
一、實(shí)現(xiàn)一個(gè)簡(jiǎn)單的tableView顯示效果
實(shí)現(xiàn)效果展示:
代碼示例(使用以前在主控制器中進(jìn)行業(yè)務(wù)處理的方式)
1.新建一個(gè)項(xiàng)目,讓控制器繼承自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.根據(jù)plist文件,字典轉(zhuǎn)模型
新建一個(gè)類,繼承自NSObject,作為數(shù)據(jù)的模型
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
/**
*應(yīng)用名稱
*/
@property(nonatomic,copy)NSString *name;
/**
* 應(yīng)用圖片
*/
@property(nonatomic,copy)NSString *icon;
/**
* 應(yīng)用的下載量
*/
@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;
}
//工廠方法
+(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];
//字典轉(zhuǎn)模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
}
#pragma mark-數(shù)據(jù)源方法
-(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;
//下載圖片數(shù)據(jù)
NSLog(@"加載圖片數(shù)據(jù)---%@", [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
說(shuō)明:上面的下載圖片數(shù)據(jù)部分是一個(gè)非常耗時(shí)的操作,這個(gè)操作任務(wù)在主線程完成,會(huì)嚴(yán)重的影響到用戶體驗(yàn),造成UI卡的現(xiàn)象。下面通過(guò)自定義NSOperation,新開(kāi)線程,讓加載圖片的任務(wù)異步執(zhí)行。
1.通過(guò)代理
在上面的基礎(chǔ)上,新建一個(gè)類,讓其繼承自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-設(shè)置代理和代理方法
@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(), ^{//回到主線程,傳遞數(shù)據(jù)給代理對(duì)象
[self.delegate downLoadOperation:self didFishedDownLoad:imgae];
});
}
}
@end
主控制器中的業(yè)務(wù)邏輯:
//
// 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];
//字典轉(zhuǎn)模型
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];
//設(shè)置最大并發(fā)數(shù)為3
_queue.maxConcurrentOperationCount=3;
}
return _queue;
}
#pragma mark-數(shù)據(jù)源方法
-(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;
//下載圖片數(shù)據(jù)
// NSLog(@"加載圖片數(shù)據(jù)---%@", [NSThread currentThread]);
// NSURL *url=[NSURL URLWithString:app.icon];
// NSData *data=[NSData dataWithContentsOfURL:url];
// UIImage *imgae=[UIImage imageWithData:data];
// cell.imageView.image=imgae;
//創(chuàng)建一個(gè)OPeration對(duì)象
YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init];
operation.url=app.icon;
operation.indexPath=indexPath;
operation.delegate=self;
//把操作對(duì)象添加到隊(duì)列中在去
[self.queue addOperation:operation];
// NSLog(@"完成顯示");
return cell;
}
-(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
{
//返回圖片數(shù)據(jù)給每行對(duì)應(yīng)的cell的imageview.image
//取出tableview中indexPath這一行對(duì)應(yīng)的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
說(shuō)明:通過(guò)打印可以發(fā)現(xiàn)上面的代碼存在很大的問(wèn)題。
問(wèn)題1:需要保證一個(gè)url對(duì)應(yīng)一個(gè)operation對(duì)象。
問(wèn)題2:下載完需要移除。移除執(zhí)行完畢的操作。
問(wèn)題3:保證一個(gè)url對(duì)應(yīng)一個(gè)image。
下面對(duì)主控制器中得代碼進(jìn)行改進(jìn):
//
// 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];
//字典轉(zhuǎn)模型
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];
//設(shè)置最大并發(fā)數(shù)為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-數(shù)據(jù)源方法
-(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;
//保證一個(gè)url對(duì)應(yīng)一個(gè)image對(duì)象
UIImage *image=self.images[app.icon];
if (image) {//緩存中有圖片
cell.imageView.image=image;
}else // 緩存中沒(méi)有圖片,得下載
{
//先設(shè)置一張占位圖片
cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];
YYdownLoadOperation *operation=self.operations[app.icon];
if (operation) {//正在下載
//什么都不做
}else //當(dāng)前沒(méi)有下載,那就創(chuàng)建操作
{
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.移除執(zhí)行完畢的操作
[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
打印查看:
- iOS多線程開(kāi)發(fā)——NSThread淺析
- IOS多線程實(shí)現(xiàn)多圖片下載(一)
- IOS多線程實(shí)現(xiàn)多圖片下載(二)
- 詳解iOS多線程GCD的使用
- 實(shí)例解析iOS應(yīng)用多線程開(kāi)發(fā)中NSthread類的用法
- 詳解iOS中多線程app開(kāi)發(fā)的GCD隊(duì)列的使用
- IOS多線程開(kāi)發(fā)之線程的狀態(tài)
- 在IOS中為什么使用多線程及多線程實(shí)現(xiàn)的三種方法
- IOS多線程編程的3種實(shí)現(xiàn)方法
- 淺析iOS應(yīng)用開(kāi)發(fā)中線程間的通信與線程安全問(wèn)題
- 理解iOS多線程應(yīng)用的開(kāi)發(fā)以及線程的創(chuàng)建方法
- iOS多線程應(yīng)用開(kāi)發(fā)中使用NSOperation類的基本方法
- iOS應(yīng)用程序中通過(guò)dispatch隊(duì)列控制線程執(zhí)行的方法
相關(guān)文章
iOS實(shí)現(xiàn)底部彈出PopupWindow效果 iOS改變背景透明效果
這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)底部彈出PopupWindow效果,iOS改變背景透明效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07NSURLSession跨域重定向透?jìng)鱄TTP Header問(wèn)題解決
這篇文章主要為大家介紹了NSURLSession跨域重定向透?jìng)鱄TTP Header問(wèn)題解決方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11ios的手勢(shì)操作之UIGestureRecognizer淺析(推薦)
本篇文章主要介紹了ios的手勢(shì)操作之UIGestureRecognizer淺析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。2016-12-12iOS 正則表達(dá)式判斷手機(jī)號(hào)碼、固話
本文主要介紹了iOS 正則表達(dá)式判斷手機(jī)號(hào)碼、固話,以及匹配是否是移動(dòng)/聯(lián)通/電信手機(jī)號(hào)的方法。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-03-03