本期呢,由小弟带大家走进Object-C中的线程系列:NSOperation


我们正常的理解就是,先创建一个后台线程,然后将这个线程放入到队列中,后台来执行一些相对耗时的方法,等该方法处理结束以后,我们再切换到主线程来进行UI的更新


NSOperation本身是抽象基类,所以我们来使用它的子类来处理


我们来介绍下它的两个子类吧


使用NSInvocationOperation\NSBlockOperation

我们还需要一个队列:NSOperationQueue


NSInvocationOperation:直面翻译是调用操作的意思,没错,在这里,我们就是要调用操作,将操作放入线程当中,说白了,就是由线程来执行这个操作,再将线程放入队列当中,然后再来做后续的处理,我们可以随时对它们进行取消


NSBlockOperation:直面翻译是块操作的意思,没错,在这里,我们就是要一块一块的操作,但我们不用将操作放进队列当中,而是添加执行块,来进行多任务并发处理,也许系统内部已经做好了封装


NSOperationQueue:直面翻译是操作队列的意思,没错,就是存放线程的一个队列,线程上会有相关的操作哦,反正我就是这么理解的咯


首先是NSInvocationOperation


 
- (void)buildOperation {
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startOperation) object:nil];
    [operation start];
}

- (void)startOperation {
    //看前面的log这时候你会发现这里面的方法其实是后台操作,也就是后台线程来做这件事情
    NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
    NSError *error;
    NSString *dataString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
    NSLog(@"start");
    if (dataString) {
        [self performSelectorOnMainThread:@selector(completeOperation:) withObject:dataString waitUntilDone:NO];
    } else {
        NSLog(@"%@", error);
    }
}

- (void)completeOperation:(NSString *)dataString {
    NSLog(@"complete");
}


这样就完成了基本的操作,那么我们来玩有意思的事情,再创一个线程,于它后执行,看看什么效果呢


 
- (void)buildOperationNew {
    NSInvocationOperation *operationNew = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(startOperationNew) object:nil];
    [operationNew start];
}

- (void)startOperationNew {
    NSLog(@"1");
}


通过实验,你会发现,它们有先后顺序,不会出现并发的现象,那么我称它们为串行操作

如果你想让它们并发,我们可以这样做:


 
- (void)buildConcurrenceOperations {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue addOperation:operationNew];
}


你会惊奇的发现,它们变成并发的了


为了更好的解决这个问题,苹果为我们提供了第二个子类,也就是NSBlockOperation


我们来看下面的例子


 
 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"block");
    }];
    [operation addExecutionBlock:^{
        NSLog(@"anotherBlock");
    }];
    [operation addExecutionBlock:^{
        NSLog(@"oneBlock");
    }];
    [operation addExecutionBlock:^{
        NSLog(@"lastBlock");
    }];
    [operation start];



这个时候,问题又来了,如果我们取消对应的操作呢,该怎么办


没错,直接掉cancel方法就好了,NSInvocationOperation这个还好,要是NSBlockOperation的话,就比较尴尬了,所以说它们各有各的好处,灵活运用才是最佳的方案


接下来我们来做个总结


NSBlockOperation跟NSInvocationOperation的区别呢,就是不用把操作放到队列里面了哦,也许它内部已经实现了放进队列的方法,只不过操作起来更方便罢了,但是需要调用start方法哦,当我们调用cancel的时候却又发现没有取消,难道它不能由我们手动去取消吗?回头我们再认真调研一次


前者是并发,后者是串行,应该可以这么理解吧



哈,如有不对的地方,还望小伙伴们纠正哦



这期就到这里咯,我们下期再见,欢迎来群里找我玩哦