iOS多線程應用開發中自訂NSOperation類的執行個體解析_IOS

來源:互聯網
上載者:User

一、實現一個簡單的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


列印查看:

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.