【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!";
    });
}];
原文地址:https://www.cnblogs.com/mamamia/p/12268801.html