zoukankan      html  css  js  c++  java
  • 【iOS 入门】对比android handler学习NSOpration

    iOS 和 android 都有主线程的概念。这点十分相似。

    android 中 更新UI 通过  handler looper messagequee来处理。iOS有类似机制。

    通过NSOpration 是其中一种。

    现在对学习 NSOpration

    java中开起线程有多种方法 Callable、Thread、 Executor线程池发起等。

    iOS同样有NSThread GCD NSOpration等。

    本文先只讨论 NSOpration

    理解方式:NSOpration 接近于 java线程池。也就是Executor  

    NSInvocationOperation: 单个任务线程执行 通过SEL去执行一个方法。(SEL 理解为 方法指针)。

    例子:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 可以传递一个 NSObject 给operation的操作方法
        NSDictionary *dict = [NSDictionary dictionaryWithObject:@"value1" forKey:@"key1"];
        NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationSelector:) object:dict];
        NSLog(@"start before");
        [op start];
        NSLog(@"start after");
    }
    
    // NSInvocationOperation 操作执行的方法
    - (void)operationSelector:(NSDictionary *)dict
    {
        // 接收传进来的dict
        NSLog(@"dictValue = %@", [dict valueForKey:@"key1"]);
        sleep(10);  // 加个睡眠模仿耗时操作
        NSLog(@"currentThread = %@", [NSThread currentThread]);
        NSLog(@"mainThread = %@", [NSThread mainThread]);
    }

    这个代码类似于:

     不同之处是SEL可以指向任何方法,executor需要的是Runnable对象。

     

     

    NSBlockOperation  其实 NSInvocationOperation 是一样的。

    SEL 换成 block而矣。 其实两者都是方法指针。真正目的都是执行一段代码块。

    addExecutionBlock 可以加入多个block 并且是异步执行的。

     

    例子:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"BlockOperation 1 begin");
            sleep(10);  // 加个睡眠模仿耗时操作
            NSLog(@"BlockOperation 1 currentThread = %@", [NSThread currentThread]);
            NSLog(@"BlockOperation 1 mainThread    = %@", [NSThread mainThread]);
            NSLog(@"BlockOperation 1 end");
        }];
        [op addExecutionBlock:^{
            NSLog(@"BlockOperation 2 begin");
            sleep(10);
            NSLog(@"BlockOperation 2 currentThread = %@", [NSThread currentThread]);
            NSLog(@"BlockOperation 2 mainThread    = %@", [NSThread mainThread]);
            NSLog(@"BlockOperation 2 end");
        }];
        [op addExecutionBlock:^{
            NSLog(@"BlockOperation 3 begin");
            sleep(10);
            NSLog(@"BlockOperation 3 currentThread = %@", [NSThread currentThread]);
            NSLog(@"BlockOperation 3 mainThread    = %@", [NSThread mainThread]);
            NSLog(@"BlockOperation 3 end");
        }];
        
        NSLog(@"start before");
        [op start];
        NSLog(@"start after");
    }

    接下去应该是:  NSOperationQueue  

    可以看出是operation队列。但不能直观理解是FIFO

    例子:

      

    - (void)viewDidLoad {
        [super viewDidLoad];
        // 创建3个 NSInvocationOperation 操作
        NSOperationQueue *opQueue = [NSOperationQueue new];
        for (NSUInteger i = 0; i < 3; i++) {
            // 可以传递一个 NSObject 给operation的操作方法
            NSDictionary *dict = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Operation_%lu", i] forKey:@"key"];
            NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationSelector:) object:dict];
            [opQueue addOperation:op];
        }
    }
        
    // NSInvocationOperation 操作执行的方法
    - (void)operationSelector:(NSDictionary *)dict
    {
        // 接收传进来的dict
        NSLog(@"dictValue = %@", [dict valueForKey:@"key"]);
        sleep(10);  // 加个睡眠模仿耗时操作
        NSLog(@"currentThread = %@", [NSThread currentThread]);
        NSLog(@"mainThread    = %@", [NSThread mainThread]);
    }
    2 NSOperationQueue 的其他属性
    添加操作有3个方法:
    
    // 直接添加一个 NSOperation 操作,并且加入并发队列,只要当前队列允许,就会立刻执行。
    - (void)addOperation:(NSOperation *)op;
    // 添加一组操作,如果 waitUntilFinished 为 NO,则必须在当前队列中的所有操作都执行完了,才会执行这组操作,否则立刻执行。
    - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);
    // 直接在这里写一个block,block中的操作加入并发队列,并且只要当前队列允许执行,就会立刻执行。
    - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);
    接下来看其他的属性
    
    // 返回当前队列中的所有操作NSOperation
    @property (readonly, copy) NSArray<__kindof NSOperation *> *operations;
    // 返回当前队列中的操作数量,对应 operations.count
    @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);
    // 可读写的属性,当设备性能不足或根据需求要限制并行的操作数量时,可以设置这个值。
    // 设置了这个值之后,队列中并发执行的操作数量不会大于这个值。超出这个值在排队中的操作会处于休眠状态。
    // 默认值为 NSOperationQueueDefaultMaxConcurrentOperationCount = -1
    @property NSInteger maxConcurrentOperationCount;
    // 可以给队列指定一个名字用来做标识
    @property (nullable, copy) NSString *name NS_AVAILABLE(10_6, 4_0);
    // 给队列指定一个优先级,默认为 NSQualityOfServiceDefault = -1
    @property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
    // ??? 这个不是太理解
    @property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue NS_AVAILABLE(10_10, 8_0);
    // 取消队列中的所有操作。其实就是调用 operations 中每个操作的`cancel`方法才取消操作。
    // 但是,在前面的文章中说过,调用`cancel`方法并不会终止操作,而是设置`cancelled`属性为 YES,
    // 这就需要自己在操作中分节点去判断`cancelled`属性了,在适当的时机结束操作。
    - (void)cancelAllOperations;
    // 调用这个方法时,会判断 NSOperationQueue 中的操作是否全部执行完,如果没有,则调用者所在的线程会在调用处等待。
    // 直到 NSOperationQueue 中的所有操作执行完成,当前线程才继续执行。如果 NSOperationQueue 为空,则该方法立刻返回。
    - (void)waitUntilAllOperationsAreFinished;
    // 取得调用者的当前线程中的 NSOperationQueue 操作队列
    + (nullable NSOperationQueue *)currentQueue NS_AVAILABLE(10_6, 4_0);
    
    // 取得主线程中的 
    + (NSOperationQueue *)mainQueue NS_AVAILABLE(10_6, 4_0);
    @property (getter=isSuspended) BOOL suspended;

    本次重点为对比handler: 用得到是

    // 取得主线程中的 
    + (NSOperationQueue *)mainQueue NS_AVAILABLE(10_6, 4_0);
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // UI更新代码
        self.alert.text = @"Thanks!";
        }];
    NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init];
    [waitQueue addOperationWithBlock:^{
        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
        // 同步到主线程
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.alert.text = @"Thanks!";
        }];
    }];


    同时提一下还有其它两种UI更新方式
    performSelectorOnMainThread
    NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init];
    [waitQueue addOperationWithBlock:^{
        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
        // 同步到主线程
        [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:NO];
    }];
    
    /**
     * UI更新函数
     */
    - (void)updateUI {
        self.alert.text = @"Thanks!";
    }
    dispatch_async(dispatch_get_main_queue(), ^{});
    NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init];
    [waitQueue addOperationWithBlock:^{
        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
        // 同步到主线程
        dispatch_async(dispatch_get_main_queue(), ^{
            self.alert.text = @"Thanks!";
        });
    }];
  • 相关阅读:
    C#实现仪器的自动化控制
    .Net FrameWork常用类
    编码:隐匿在计算机软硬件背后的语言(8)--自动操作(三)
    深入理解计算机系统(4)-- 整数和浮点数
    编码:隐匿在计算机软硬件背后的语言(8)--自动操作(二)
    C#中二进制、十进制和十六进制互相转换的方法
    深入理解计算机系统(3)-- 信息存储
    mysql-5.7.17-winx64免安装版环境配置 问题小记
    python生成随机数:uniform(), randint(), gauss(), expovariate()
    深度学习翻译 效果优于各类翻译器
  • 原文地址:https://www.cnblogs.com/mamamia/p/12268801.html
Copyright © 2011-2022 走看看