iOS開發實踐之cell下載圖片(自訂NSOperation)

來源:互聯網
上載者:User

iOS開發實踐之cell下載圖片(自訂NSOperation)

上一篇文章的下載圖片操作都放在了block中,當遇到複雜的操作,一堆的代碼放在block中 ,很明顯這不是明智的選擇,代碼顯得很臃腫。 因此,把線程操作放到自訂NSOperation中。

自訂NSOperation的步驟:繼承NSOperation、重寫- (void)main方法,在裡面實現想執行的任務。

重寫- (void)main方法的注意點:

1、自己建立自動釋放池(因為如果是非同步作業,無法訪問主線程的自動釋放池)。

2、經常通過- (BOOL)isCancelled方法檢測操作是否被取消,對取消做出響應。

案例代碼:

1、建立DownloadOperation繼承NSOperation,下載操作放到main方法中。 至於下載後回到主線程要做點什麼,它自己本身不知道(不是它的工作範疇)。只負責下載完成後通知其它人,因此委託代理,委託別人去做事。

DownloadOperation.h

#import #import @class DownloadOperation;//協議@protocol DownloadOperationDelegate @optional- (void)downloadOperation:(DownloadOperation *)operation didFinishDownload:(UIImage *)image;@end@interface DownloadOperation : NSOperation//下載圖片地址@property(nonatomic,copy) NSString *imageUrl;//表格cell位置@property(nonatomic,strong) NSIndexPath *indexPath;//代理@property(nonatomic,weak) id delegate;@end

DownloadOperation.m

注意:@autoreleasepool自動釋放池 、isCancelled方法檢測操作是否被取消,對取消做出響應。

#import "DownloadOperation.h"#import @implementation DownloadOperation-(void)main{    @autoreleasepool {//管理記憶體        if (self.isCancelled)  return;  //暫停為執行的操作                NSURL *url = [NSURL URLWithString:self.imageUrl];        NSData *data = [NSData dataWithContentsOfURL:url]; // 下載        UIImage *image = [UIImage imageWithData:data]; // NSData -> UIImage                if(self.isCancelled) return;//暫停正在執行的操作                // 回到主線程        [[NSOperationQueue mainQueue] addOperationWithBlock:^{            if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {                [self.delegate downloadOperation:self didFinishDownload:image];            }        }];    }}@end

2、AppsTableViewController.m

////  AppsTableViewController.m//  cell圖片下載(自訂operation)#import "AppsTableViewController.h"#import "App.h"#import "DownloadOperation.h"@interface AppsTableViewController ()//應用資訊集合@property(nonatomic,strong) NSMutableArray *apps;//存放所有下載圖片的隊列@property(nonatomic,strong) NSOperationQueue *queue;//存放所有的下載操作(url是key,operation對象是value)@property(nonatomic,strong) NSMutableDictionary *operations;//存放所有下載完的圖片@property(nonatomic,strong) NSMutableDictionary *images;@end@implementation AppsTableViewController- (void)viewDidLoad {    [super viewDidLoad];    }- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}/** * 懶載入 **/-(NSMutableArray *)apps{    if (!_apps) {        NSMutableArray *appArr = [NSMutableArray array];        NSString *file =[[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];        NSArray *dictArr = [NSArray arrayWithContentsOfFile:file];        for (NSDictionary *dict in dictArr) {            App *app = [App appWithDict:dict];            [appArr addObject:app];        }        _apps = appArr;    }    return _apps;}-(NSOperationQueue *)queue{    if (!_queue) {        _queue = [[NSOperationQueue alloc]init];    }    return _queue;}-(NSMutableDictionary *)operations{    if (!_operations) {        _operations = [[NSMutableDictionary alloc]init];    }    return _operations;}-(NSMutableDictionary *)images{    if (!_images) {        _images = [[NSMutableDictionary alloc]init];    }    return _images;}#pragma mark - Table view data source- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {    return 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    return self.apps.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    static NSString *ID = @"app";    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];    if (!cell) {        cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];    }        App *app = self.apps[indexPath.row];    cell.textLabel.text = app.name;    cell.detailTextLabel.text = app.download;        // 先從images緩衝中取出圖片url對應的UIImage    UIImage *image = self.images[app.icon];    if (image) {// 說明圖片已經下載成功過(成功緩衝)        cell.imageView.image = image;    }else{        // 獲得caches的路徑, 拼接檔案路徑        NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[app.icon lastPathComponent]];                // 先從沙箱中取出圖片        NSData *data = [NSData dataWithContentsOfFile:file];        if (data) {//沙箱中存在圖片            cell.imageView.image = [UIImage imageWithData:data];        }else{//沙箱不存,進行下載操作            //顯示佔位圖片            cell.imageView.image = [UIImage imageNamed:@"placeholder"];                        // 下載圖片            [self download:app.icon indexPath:indexPath];        }            }    return cell;}-(void)download:(NSString *)imageUrl indexPath:(NSIndexPath *)indexPath{    //取出當前圖片url對應下的下載操作(operations對象)    DownloadOperation *operation = self.operations[imageUrl];    if (operation)  return; //如果存在操作就不往下執行(因為可能該圖片下載操作進行中)        //建立操作,下載圖片    operation = [[DownloadOperation alloc]init];    operation.imageUrl = imageUrl;    operation.indexPath = indexPath;        //設定代理    operation.delegate = self;        // 添加操作到隊列中    [self.queue addOperation:operation];         // 添加到字典中 (這句代碼為瞭解決重複下載)    self.operations[imageUrl] = operation;        }/** *  當使用者開始拖拽表格時調用 */-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView{  //暫停下載    [self.queue setSuspended:YES];}/** *  當使用者停止拖拽表格時調用 */-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{    //開始下載    [self.queue setSuspended:NO];}#pragma mark - 下載操作的代理方法-(void)downloadOperation:(DownloadOperation *)operation didFinishDownload:(UIImage *)image{    // 存放圖片到字典中    if (image) {        //存放所有的下載操作        self.operations[operation.imageUrl] = image;                //將圖片存入沙箱中        NSData *data = UIImagePNGRepresentation(image);        NSString *file = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject]stringByAppendingPathComponent:[operation.imageUrl lastPathComponent]];        [data writeToFile:file atomically:YES];    }        // 從字典中移除下載操作 (防止operations越來越大,保證下載失敗後,能重新下載)    [self.operations removeObjectForKey:operation.imageUrl];        // 重新整理表格    [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];}@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.