• iOS:操作队列实现多线程NSOperation


    NSOperation具体使用:直接继承NSObject

    它的子类有:NSBlockOperation、NSInvocationOperation
    还有一个必须的类,队列,用来装创建的线程 NSOperationQueue
     
    理解:这个方式是如何实现多线程呢?是通过操作队列来实现多线程的。即主线程是一个主队列,再创建一个队列并将其他的线程加入其中同步执行。如果对共享资源的争夺放在主线程队列中,则不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上;否则的话,仍需要关心数据同步的问题。
     
    说明:
    一般用子类创建Operation实例来实现多线程,NSBlockOperationNSInvocationOperation这两种方式均可以使用,前一个采用的是将线程的执行过程封装为block函数,第二个采用的是将线程的执行过程封装为方法。

    1、NSOperation的详解:
    队列优先级枚举:
    typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {

    NSOperationQueuePriorityVeryLow = -8L,

    NSOperationQueuePriorityLow = -4L,

    NSOperationQueuePriorityNormal = 0,

    NSOperationQueuePriorityHigh = 4,

    NSOperationQueuePriorityVeryHigh = 8

    };

    属性:
    @property (readonly, getter=isCancelled) BOOL cancelled;               //线程是否取消

    @property (readonly, getter=isExecuting) BOOL executing;              //线程是否在执行

    @property (readonly, getter=isFinished) BOOL finished;                  //线程是否执行完毕

    @property (readonly, getter=isConcurrent) BOOL concurrent;          //线程是否并发执行

    @property (readonly, getter=isAsynchronous) BOOL asynchronous; //是否线程异步,已经被线程同步覆盖

    @property (readonly, getter=isReady) BOOL ready;                       //线程是否处于就绪状态

    @property (readonly, copy) NSArray *dependencies;                      //线程依赖的数组

    @property NSOperationQueuePriority queuePriority;                  //队列优先级

    @property (copy) void (^completionBlock)(void);                           //block函数

    @property double threadPriority;                                             //线程优先级

    @property NSQualityOfService qualityOfService;                        //服务质量

    @property (copy) NSString *name;                                           //线程名字

    方法:
    - (void)start;   //启动线程
    - (void)main;   //主线程

    - (void)cancel;//取消线程

    - (void)addDependency:(NSOperation *)op; //添加线程依赖(只有上一个线程一直执行,依赖的下一个线程才开始执行)

    - (void)removeDependency:(NSOperation *)op; //移除线程依赖

    - (void)waitUntilFinished  //等待抢占资源的线程结束

    ================================================================================

    2、NSIndivocationOperation的详解:NSInvocationOperation : NSOperation

    属性:

    @property (readonly, retain) NSInvocation *invocation;    //线程的调用

    @property (readonly, retain) id result;                           

    方法:

    //创建线程的实例方法,可以添加线程事件

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

    //创建线程的实例方法

    - (instancetype)initWithInvocation:(NSInvocation *)inv ;

    =================================================================

     
    3、NSBlockOperation的详解:NSBlockOperation : NSOperation

    属性:@property (readonly, copy) NSArray *executionBlocks;   //执行block的线程队列数组

    方法:

    ※创建线程的类方法,执行block函数

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

    ※添加执行线程对列block函数

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

     

     ==========================================================

    4、NSOperationQueue队列的详解:NSOperationQueue : NSOperation

    属性:
    @property (readonly, copy) NSArray *operations;           //操作线程数组
    @property (readonly) NSUInteger operationCount           //一次能执行的线程数量

    @property NSInteger maxConcurrentOperationCount;     // 能并发执行的最大线程数量

    @property (getter=isSuspended) BOOL suspended;                  //是否暂时线程

    @property (copy) NSString *name ;                                      //线程名字

    @property NSQualityOfService qualityOfService;                     //服务质量

    @property (assign /* actually retain */) dispatch_queue_t underlyingQueue;   

    方法:

    ※添加线程

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

    ※等待添加线程数组

    - (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait;

    ※添加线程并执行block函数的实例方法

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

    ※取消所有的线程

    - (void)cancelAllOperations;

    ※等待所有的线程执行完毕

    - (void)waitUntilAllOperationsAreFinished;

    ※当前队列

    + (NSOperationQueue *)currentQueue;

    ※主队列

    + (NSOperationQueue *)mainQueue;

     
    具体举例如下:多线程卖票(将当前票数和线程名字显示在文本视图中)
     
    方法一:采用NSOpeartion的子类NSIndivocationOperation创建多线程:
    1.文本视图控件并关联以及声明票属性
    @interface ViewController ()
    {
        int tickets;
    }
    @property (weak, nonatomic) IBOutlet UITextView *textView;

    2.设置票数和文本视图

        //准备数据
        tickets = 20;
        
        //设置textView
        self.textView.text = @"";
        self.textView.layoutManager.allowsNonContiguousLayout = NO;

    3.创建NSOperation实例(线程)

    //创建NSOperation并加到队列
        NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSellMethod:) object:@"售票线程-1"];
         NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSellMethod:) object:@"售票线程-2"];

    4.将operation加入创建的队列中

        //创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        
        //为操作之间添加依赖,只有被依赖的线程执行完,依赖的线程才能执行
        //[operation1 addDependency:operation2];
        
        //将opearion放入队列
        [queue addOperation:operation1];
        [queue addOperation:operation2];

    5.更新UI的主线程队列

    #pragma mark -更新UI
    -(void)appendTextView:(NSString *)text
    {
        //1.获取原来的内容
        NSMutableString *content = [[NSMutableString alloc]initWithString:self.textView.text];
        NSRange range = NSMakeRange(content.length, 1);
    
        //2.追加新的内容
        [content appendString:[NSString stringWithFormat:@"
    %@",text]];
        [self.textView setText:content];
        
        
        //3.滚动视图
        [self.textView scrollRangeToVisible:range];
    }

    6.执行对共享抢占资源操作的过程

    #pragma mark -执行线程过程

    -(void)operationSellMethod:(NSString*)name
    {
        while (YES)
        {
            //1.判断是否有票
            if (tickets>0)
            {
                //没有将共享抢占资源放到主队列中,仍然要关心数据同步的问题
             @synchronized(self)
                {
                    NSString *info = [NSString stringWithFormat:@"总的票数:%d,当前的线程:%@",tickets,name];
                    
                    [[NSOperationQueue mainQueue]addOperationWithBlock:^{
                        [self appendTextView:info];
                    }];
                    
                    //2.卖票
                    tickets--;
                }
                
                //3.线程休眠
                if([name isEqualToString:@"售票线程-1"])
                {
                    [NSThread sleepForTimeInterval:0.3f];
                }
                else
                {
                    [NSThread sleepForTimeInterval:0.2f];
                }
            }
            else
            {
                //更新UI
                NSString *info = [NSString stringWithFormat:@"票已经售完,当前的线程:%@",name];
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    [self appendTextView:info];
                }];
                
                //退出线程
                break;
            }
        }
    }

    方法二:采用NSOpeartion的子类NSBlockOperation创建多线程:

    1.文本视图控件并关联以及声明票属性
    @interface ViewController ()
    {
        int tickets;
    }
    @property (weak, nonatomic) IBOutlet UITextView *textView;

    2.设置票数和文本视图

        //准备数据
        tickets = 20;
        
        //设置textView
        self.textView.text = @"";
        self.textView.layoutManager.allowsNonContiguousLayout = NO;

    3.创建队列和操作block线程

        //创建队列
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        
        //设置并行的线程数量
        //[queue setMaxConcurrentOperationCount:2];
        
        //在队列中添加block的operation
        [queue addOperationWithBlock:^{
            [self operationSellMethod:@"售票线程-1"];
        }];
        
        
        [queue addOperationWithBlock:^{
            [self operationSellMethod:@"售票线程-2"];
        }];
        
        
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            [self operationSellMethod:@"售票线程-3"];
        }];
        [queue addOperation:blockOperation];

    4.更新UI的主线程队列

    #pragma mark -更新UI
    -(void)appendTextView:(NSString *)text
    {
        //1.获取原来的内容
        NSMutableString *content = [[NSMutableString alloc]initWithString:self.textView.text];
        NSRange range = NSMakeRange(content.length, 1);
    
        //2.追加新的内容
        [content appendString:[NSString stringWithFormat:@"
    %@",text]];
        [self.textView setText:content];
        
        
        //3.滚动视图
        [self.textView scrollRangeToVisible:range];
    }

    5.执行对共享抢占资源操作的过程

    #pragma mark -执行线程过程

    #pragma mark -执行线程过程
    -(void)operationSellMethod:(NSString*)name
    {
        while (YES)
        {
            //1.判断是否有票
            if (tickets>0)
            {
                //将共享抢占资源放入主队列,不需要再关心数据同步的问题
                [[NSOperationQueue mainQueue]addOperationWithBlock:^{
                 
                    NSString *info = [NSString stringWithFormat:@"总的票数:%d,当前的线程:%@",tickets,name];
                    
                    [self appendTextView:info];
                    
                    //2.卖票
                    tickets--;
                }];
    
                            
                //3.线程休眠
                if([name isEqualToString:@"售票线程-1"])
                {
                    [NSThread sleepForTimeInterval:0.3f];
                }
                else
                {
                    [NSThread sleepForTimeInterval:0.2f];
                }
            }
            else
            {
                //更新UI
                NSString *info = [NSString stringWithFormat:@"票已经售完,当前的线程:%@",name];
                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    [self appendTextView:info];
                }];
                
                //退出线程
                break;
            }
        }
    }

     演示结果如下:

     
     

     
  • 相关阅读:
    .net 面试题之 输出 空 三角型
    js 里 用XML httpRequest 调用 Web Service
    C# 设计模式之 单例模式
    C#TreeView 实现无线级别分类
    asp.net Session的原理
    .Net 面试题之 查询两个时间差
    暑 假 队 测 Round #2
    两个排序算法的扩展应用
    暑 假 队 测 Round #1
    二维单调队列或st表
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/4857898.html
Copyright © 2020-2023  润新知