• iOS开发多线程基础知识 NSOperation


    -------NSOperation简介----
    1.NSOperation的作用
    ·配合使用NSOperation和NSOperationQueue也能实现多线程编程
     
    2.NSOperation和NSOperationQueue实现多线程的具体步骤
    ·先将需要执行的操作封装到一个NSOperation对象中
    ·然后将NSOperation对象添加到NSOperationQueue中
    ·系统会自动将NSOperation中封装的操作放到一条新线程中执行
     
    ---------NSOperation的子类----
    3.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
     
    4.使用NSOperation子类的方式有3种
    ·NSInvocationOperation
    ·NSBlockOperation
    ·自定义子类继承NSOperation,实现内部相应的方法
     
    ------NSInvocationOperation---
    5.创建NSInvocationOperation对象

    - (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

    6.调用start方法开始执行操作

    - (void)start;

    一旦执行操作,就会调用target的sel方法

    7.注意
    ·默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
    ·只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
     
     
    -------NSBlockOperation--
    8.创建NSBlockOperation对象

    + (id)blockOperationWithBlock:(void (^)(void))block;

    9.通过addExecutionBlock:方法添加更多的操作

    - (void)addExecutionBlock:(void (^)(void))block;

    注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作

    -------NSOperationQueue----

    10.NSOperationQueue的作用
    ·NSOperation可以调用start方法来执行任务,但默认是同步执行的
    ·如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
     
    11.添加操作到NSOperationQueue中

    - (void)addOperation:(NSOperation *)op;

    - (void)addOperationWithBlock:(void (^)(void))block;

    -------最大并发数----

    12.什么是并发数
    ·同时执行的任务数
    ·比如,同时开3个线程执行3个任务,并发数就是3
     
    13.最大并发数的相关方法

    - (NSInteger)maxConcurrentOperationCount;

    - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

    -----队列的取消、暂停、恢复------

    14.取消队列的所有操作

    - (void)cancelAllOperations;

    提示:也可以调用NSOperation的- (void)cancel方法取消单个操作

    15.暂停和恢复队列

    - (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列

    - (BOOL)isSuspended;

    ----操作优先级-----

    16.设置NSOperation在queue中的优先级,可以改变操作的执行顺序

    - (NSOperationQueuePriority)queuePriority;

    - (void)setQueuePriority:(NSOperationQueuePriority)p;

    17.优先级的取值(优先级越高,越先执行)
    ·NSOperationQueuePriorityVeryLow = -8L,
    ·NSOperationQueuePriorityLow = -4L,
    ·NSOperationQueuePriorityNormal = 0,
    ·NSOperationQueuePriorityHigh = 4,
    ·NSOperationQueuePriorityVeryHigh = 8
     
    ---操作依赖---
    18.NSOperation之间可以设置依赖来保证执行顺序
    ·比如一定要让操作A执行完后,才能执行操作B,可以这么写

    [operationB addDependency:operationA]; // 操作B依赖于操作A

    19.可以在不同queue的NSOperation之间创建依赖关系

    20.注意:不能相互依赖

    ·比如A依赖B,B依赖A
    ----操作的执行顺序---
    21.对于添加到queue中的operations,它们的执行顺序取决于2点
    ·首先依据NSOperation之间的依赖关系
    ·然后依据NSOperation的优先级
     
    22.因此,总体的执行顺序是
    ·先满足依赖关系
    ·然后再从NSOperation中选择优先级最高的那个执行
     
     
     
    ---自定义NSOperation---
    23.自定义NSOperation的步骤很简单
    ·重写- (void)main方法,在里面实现想执行的任务
     
    24.重写- (void)main方法的注意点
    ·自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
    ·经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
     
     
     
    --------分割线---
    NSOperation小代码1,
    只写一个文件参考下
    //  DYFViewController.m
    //  624-03-NSOperation
    //
    //  Created by dyf on 14-6-24.
    //  Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved.
    //
    
    #import "DYFViewController.h"
    
    @interface DYFViewController ()
    
    @end
    
    @implementation DYFViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	// Do any additional setup after loading the view, typically from a nib.
        
      
        [self testOperationQueue];
    }
    
    - (void)testOperationListen {
        NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"下载图片1111111%@", [NSThread currentThread]);
            // 下载图片
        }];
        operation3.completionBlock = ^{
            // 下载完图片后想做的时期
        };
        // 2.创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
        [queue addOperation:operation3];
    
    }
    
    - (void)testOperationQueue {
        // 1.封装操作
        NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
        NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
        
        NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"1111111%@", [NSThread currentThread]);
        }];
        
        [operation3 addExecutionBlock:^{
            NSLog(@"222222%@", [NSThread currentThread]);
        }];
        [operation3 addExecutionBlock:^{
            NSLog(@"33333%@", [NSThread currentThread]);
        }];
        // 2.创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        // 5以内,2~3为宜
        queue.maxConcurrentOperationCount = 2;
    #warning 面试题
        // 设置操作依赖(一定要在添加到队列中前设置)
        [operation2 addDependency:operation1]; // 执行顺序取决于依赖,先执行完operation1再执行operation2
    // 注意:不能相互依赖,循环操作
        
        // 3.添加操作到队列中(自动执行操作,自动开启线程)
        [queue addOperation:operation1];
        [queue addOperation:operation2];
        [queue addOperation:operation3];
        
        // 取消所有线程
        //[queue cancelAllOperations];
        
        // 暂停队列
        //[queue setSuspended:YES];
        
        // 设置操作优先级
        //operation1.queuePriority = NSOperationQueuePriorityVeryHigh;
        
        
    }
    
    - (void)testNSBlockOperation {
        // 1.创建操作对象,封装要执行的任务
        NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
            for (int i = 0; i < 11; i++) {
                NSLog(@"1111111%@", [NSThread currentThread]);
            }
        }];
        // 任务数在2各以上,就会开线程
        [operation addExecutionBlock:^{
            for (int i = 0; i < 11; i++) {
                NSLog(@"222222%@", [NSThread currentThread]);
            }
        }];
        [operation addExecutionBlock:^{
            for (int i = 0; i < 11; i++) {
                NSLog(@"33333%@", [NSThread currentThread]);
            }
        }];
    
        // 2.执行操作
        [operation start];
    }
    
    - (void)testNSInvocationOperation {
        // 1.创建操作对象,封装要执行的任务
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
        // 2.执行操作(默认情况下,若操作没有放到队列queue中,都是同步执行)
        [operation start];
    }
    
    - (void)download
    {
        for (int i = 0; i < 11; i++) {
            NSLog(@"download-----%@", [NSThread currentThread]);
        }
    }
    
    - (void)run
    {
        for (int i = 0; i < 11; i++) {
            NSLog(@"run------%@", [NSThread currentThread]);
        }
    }
    
    @end
    

    ----自定义NSOperation---

    //
    //  DYFDownloadOperation.h
    //  624-05-自定义Operation
    //
    //  Created by dyf on 14-6-24.
    //  Copyright (c) 2014年 dyf. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @class DYFDownloadOperation;
    @protocol DYFDownloadOperationDelegate <NSObject>
    
    @optional
    - (void)downloadOperation:(DYFDownloadOperation *)operation didFinishedDownload:(UIImage *)image;
    
    @end
    
    @interface DYFDownloadOperation : NSOperation
    
    @property (nonatomic, copy) NSString *url;
    @property (nonatomic, strong) NSIndexPath *indexPath;
    
    @property (nonatomic, weak) id<DYFDownloadOperationDelegate> delegate;
    
    @end
    
    //
    //  DYFDownloadOperation.m
    //  624-05-自定义Operation
    //
    //  Created by dyf on 14-6-24.
    //  Copyright (c) 2014年 dyf. All rights reserved.
    //
    
    #import "DYFDownloadOperation.h"
    
    @implementation DYFDownloadOperation
    /**
     *  在main方法中实现具体操作
     */
    - (void)main
    {
        @autoreleasepool {
            if (self.isCancelled) return;
            NSURL *imaUrl = [NSURL URLWithString:self.url];
            if (self.isCancelled) return;
            // 下面这行很耗时
            NSData *data = [NSData dataWithContentsOfURL:imaUrl];
            if (self.isCancelled) return;
            UIImage *image = [UIImage imageWithData:data];
            if (self.isCancelled) return;
            
            // 返回主线程显示图片
            // 通过代理
            if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishedDownload:)]) {
                [self.delegate downloadOperation:self didFinishedDownload:image];
            }
        }
    }
    
    @end
    

    具体利用MVC模式创建的文件老生常谈,只来一个Controller.m文件供参考,数据存储存在问题,可以改用SDWebImage框架处理

    //
    //  DYFTableViewController.m
    //  624-05-自定义Operation
    //
    //  Created by dyf on 14-6-24.
    //  Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved.
    //
    
    #import "DYFTableViewController.h"
    #import "DYFAppModel.h"
    #import "DYFDownloadOperation.h"
    
    #warning Dictionary基础知识不太理解,字典的赋值回去看看笔记
    @interface DYFTableViewController ()<DYFDownloadOperationDelegate>
    
    @property (nonatomic, strong) NSArray *apps;
    @property (nonatomic, strong) NSOperationQueue *queue;
    
    /**
     *  key:url   value:operation对象
     */
    @property (nonatomic, strong) NSMutableDictionary *oprations;
    /**
     *  key:url   value:image对象
     */
    @property (nonatomic, strong) NSMutableDictionary *images;
    
    @end
    
    @implementation DYFTableViewController
    
    #pragma mark - 4个懒加载
    - (NSArray *)apps
    {
        if (!_apps) {
            NSString *path = [[NSBundle mainBundle] pathForResource:@"apps" ofType:@"plist"];
            NSArray *arrayApps = [NSArray arrayWithContentsOfFile:path];
            
            NSMutableArray *arrayM = [NSMutableArray arrayWithCapacity:arrayApps.count];
            for (NSDictionary *dict in arrayApps) {
                DYFAppModel *appM = [DYFAppModel appWithDict:dict];
                [arrayM addObject:appM];
            }
            _apps = arrayM;
        }
        return _apps;
    }
    - (NSOperationQueue *)queue
    {
        if (!_queue) {
            _queue = [[NSOperationQueue alloc] init];
            // 设置最大并发线程数,最多同时下载3张图片
            _queue.maxConcurrentOperationCount = 3;
        }
        return _queue;
    }
    - (NSMutableDictionary *)oprations
    {
        if (!_oprations) {
            _oprations = [[NSMutableDictionary alloc] init];
        }
        return _oprations;
    }
    - (NSMutableDictionary *)images
    {
        if (!_images) {
            _images = [NSMutableDictionary dictionary];
        }
        return _images;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	// Do any additional setup after loading the view, typically from a nib.
    }
    
    #pragma mark - 数据源方法
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.apps.count;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        // 1.创建cell
        static NSString *identifier = @"apps";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
        }
        // 2.设置cell的数据
        DYFAppModel *app = self.apps[indexPath.row];
        cell.textLabel.text = app.name;
        cell.detailTextLabel.text = app.download;
        
        // 重点是如何从网络下载图片传入cell上面
        // 每个url对应一个DYFDownloadOperation对象
        // 每个url对应一个image对象
        UIImage *image = self.images[app.icon];
        if (image) {
            // 若缓存中存在图片
            cell.imageView.image = image;
        }else
        {
            // 若缓存中不存在图片,则图片要从网上下载
            // 设置下载前系统刷出的图片
            cell.imageView.image = [UIImage imageNamed:@"身份证小"];
            
            // 基础差,下面这行不太理解
            DYFDownloadOperation *operation = self.oprations[app.icon];
            if (operation) {
                // 若正在下载,则不执行其它操作
            }else
            {
                // 若没在下载,则创建开始下载的子线程
                DYFDownloadOperation *operation = [[DYFDownloadOperation alloc] init];
                operation.url = app.icon;
                operation.indexPath = indexPath;
                operation.delegate = self;
                // 添加任务进队列,异步下载
                [self.queue addOperation:operation];
                // 基础差,下面这行不太理解
                self.oprations[app.icon] = operation;
            }
        }
        
        // 3.返回cell
        return cell;
    }
    
    #pragma mark - DYFDownloadOperationDelegate
    - (void)downloadOperation:(DYFDownloadOperation *)operation didFinishedDownload:(UIImage *)image
    {
        // 1.删除执行完毕的下载操作
        [self.oprations removeObjectForKey:operation.url];
        // 若图片下载好
        if (image) {
            // 2.将下载好的图片存入缓存
            self.images[operation.url] = image;
            // 3.刷新这一行cell的数据
            [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];
            // 4.将图片存入沙盒
            
            // 4.1图片先转换为2进制数据
            NSData *data = UIImagePNGRepresentation(image);
            // 4.2设置沙盒路径
            NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[self.apps[operation.indexPath.row] icon]];
            NSLog(@"%@", path);
            // 4.3保存data到path中
            [data writeToFile:path atomically:YES];
        }
    }
    
    // 开始拖拽时候暂停队列
    - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
    {
        [self.queue setSuspended:YES];
    }
    // 停止拖拽的时候重启队列
    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
    {
        [self.queue setSuspended:NO];
    }
    
    @end
    
     
  • 相关阅读:
    deepin 配置开发环境
    Springcloud学习笔记(一)总述
    Linux(Centos7) 配置 Tomcat 开机自启
    Linux下安装JDK8
    CentOS7 防火墙和端口管理
    Linux 下安装 MySQL8 教程
    WPF使用CefSharp嵌入网页
    WPF使用第三方字体(TTF字体)
    Hive学习笔记 --Permission denied: user=anonymous, access=READ
    SpringBoot jar 注册windows服务
  • 原文地址:https://www.cnblogs.com/dyf520/p/3807187.html
Copyright © 2020-2023  润新知