iOS多线程之7.NSOperation的初识

NSOperation和GCD一样,不用我们管理线程的生命周期,加锁等问题,只要把操作封装进NSOperation中,系统会自动帮我们创建线程,执行操作。而且他是面向对象的,我们看起来更容易理解,使用起来也更灵活。GCD提供的API都是C语言的,看起来确实有点头痛。   NSOperation是一个抽象类,我们得使用他的两个子类NSInvocationOperation和NSBlockOperatio才能实现多线程,当然我们也可以自定义。那下面就先介绍一下该怎么使用。

NSInvocationOperation

代码

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 初始化一个对象,并把操作(相当于GCD里的任务)封装进去
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    // 开始执行 一开始就执行run方法
    [operation start];
    
    NSLog(@"怎么才执行我");
}
- (void)run {
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"执行操作%@",[NSThread currentThread]);
}

日志

2016-11-06 08:23:38.999 TTTTTTTTTT[2872:38936] 执行操作<NSThread: 0x7a710ca0>{number = 1, name = main}
2016-11-06 08:23:38.999 TTTTTTTTTT[2872:38936] 怎么才执行我

分析: (1)操作默认在主线程中执行,看打印的第一条日志。 (2)是同步执行的,会堵塞当前线程,看第二条日志,run方法执行完,“怎么才执行我”才打印。

NSBlockOperation

代码

- (void)viewDidLoad {
    [super viewDidLoad];
   
    // 初始化,并把要执行的操作封装进block中
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        [NSThread sleepForTimeInterval:1.0];
        NSLog(@"执行操作%@",[NSThread currentThread]);
    }];
    [operation start];
    
    NSLog(@"我知道我想早点执行,那是不可能的");
}

日志

2016-11-06 08:39:16.815 TTTTTTTTTT[3528:48184] 执行操作<NSThread: 0x60800006e4c0>{number = 1, name = main}
2016-11-06 08:39:16.816 TTTTTTTTTT[3528:48184] 我知道我想早点执行,那是不可能的

分析:是不是看起来和NSInvocationOperation一样,都是同步在主线程中执行,其实NSBlockOperation是可以并发执行的;

NSBlockOperation的并发执行

代码

- (void)viewDidLoad {
    [super viewDidLoad];
   
    // 初始化,并把要执行的操作封装进block中
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        // 添加任务A
        NSLog(@"执行操作A%@",[NSThread currentThread]);
    }];
    [operation addExecutionBlock:^{
        // 添加任务B
        NSLog(@"执行操作B%@",[NSThread currentThread]);
    }];
    [operation addExecutionBlock:^{
        // 添加任务C
        NSLog(@"执行操作C%@",[NSThread currentThread]);
    }];
    [operation start];
    
}

日志

2016-11-06 08:43:48.102 TTTTTTTTTT[3707:50733] 执行操作B<NSThread: 0x60000007f200>{number = 3, name = (null)}
2016-11-06 08:43:48.102 TTTTTTTTTT[3707:50702] 执行操作A<NSThread: 0x60000007cac0>{number = 1, name = main}
2016-11-06 08:43:48.102 TTTTTTTTTT[3707:50734] 执行操作C<NSThread: 0x608000268840>{number = 4, name = (null)}

分析: (1)看到没有,操作B和C都是在子线程执行的,实现了异步并发。 (2)当NSBlockOperation里的要执行的操作的数量 >1的时,就会异步并发执行;否则(当NSBlockOperation里的要执行的操作只有一个),就会默认在主线程中同步执行。

NSOperationQueue

   NSInvocationOperation里面的操作也想异步并发执行可以不可以呢?当然没问题了,用NSOperationQueue 就行。 代码

- (void)viewDidLoad {
    [super viewDidLoad];
   
    // 初始化一个NSOperationQueue对象
    NSOperationQueue *queue= [NSOperationQueue new];
    
    NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run1) object:nil];
    // 添加操作
    [queue addOperation:operation1];
    
    NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run2) object:nil];
    // 添加操作
    [queue addOperation:operation2];
    // 还可以这样添加操作
    [queue addOperationWithBlock:^{
        NSLog(@"执行第3个操作%@",[NSThread currentThread]);
    }];
}
- (void)run1 {
    NSLog(@"执行第1个操作%@",[NSThread currentThread]);
}

- (void)run2 {
    NSLog(@"执行第2个操作%@",[NSThread currentThread]);
}

日志

2016-11-06 08:57:03.498 TTTTTTTTTT[4195:57383] 执行第2个操作<NSThread: 0x60800006f8c0>{number = 3, name = (null)}
2016-11-06 08:57:03.498 TTTTTTTTTT[4195:57384] 执行第1个操作<NSThread: 0x608000079480>{number = 4, name = (null)}
2016-11-06 08:57:03.498 TTTTTTTTTT[4195:57386] 执行第3个操作<NSThread: 0x600000079e40>{number = 5, name = (null)}

分析: (1)三个操作分别在不同的线程中执行,实现了并发。 (2)添加进队列的任务会自动执行,不要我们开启了。 [operation start];不用写了。 (3)添加进队列的任务也是遵循先进先出的FIFO准则。那有人就要问了,为什么第一个操作不是第一个先执行完?这其实和100米赛跑一个起跑的不是第一个到终点一个道理,不矛盾。

总结

  NSOperation的使用步骤和GCD没啥区别,都是确定要执行的操作,把操作放进NSOperation中,开始执行。如果想异步并发操作,在加一步,把NSOperation放进队列中。记住一点不能直接使用NSOperation,要使用它的两个子类NSInvocationOperation和NSBlockOperatio。   其实关于NSOperation还有很多基本的属性和方法,下一篇文章再讲。看到NSOperation的使用是不是舒服多了……

相关推荐