为什么要用多线程? 

       举个例子:在同一个程序里面,存在操作A,操作B。假设操作A耗时5s,操作B耗时0.1s,如果我先触发操作A,接着马上触发操作B,那么操作B的响应必定要在A结束以后才能执行;这样会影响用户体验。为什么会这样那? 因为操作A,B都在同一个线程里面,线程的执行是具有顺序性的,A操作结束,才能进行下一个B操作。 但是A操作耗时较长,用户就需要等待5s后才能看到B操作的响应。为了防止这样的事情发生,我们的方法是另外开辟一个线程。


     iOS多线程方法有以下三种:

     NSThread

     NSOperation

     GCD


      接下来我用以下例子讲述三种多线程的使用方法:

      如下界面两个label,  两个button, 点击A按钮执行操作 : 休眠5s  -> 将label1的内容变为"Good"   ;     点击B按钮: 将label2的内容直接变为“bad”

如果不使用多线程, 当点击完A之后, 马上点击B, 这个时候你会看到的过程是   A的响应完成之后,才去执行操作B, 使用多线程后, 我们会看到A,B操作互不干扰的执行。



ios 多线程 nsoperation ios 多线程 简书_ios 多线程 nsoperation



GCD:


  • GCD是一种较为底层的多线程实现方式,其原理是将操作封装为block,并加入指定队列中开辟新线程执行。
  • NSOperation以及NSOperationQueue都是对GCD机制的高层封装。
  • 使用GCD可以实现更加灵活的多线程处理。




 

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

        sleep(5); // 休眠5s

        //UI刷新的操作要在主线程中执行
        dispatch_async(dispatch_get_main_queue(), ^{

            self.label1.text =@"Good";
        });
        
    });


NSOperation:


  • NSOperation将一个操作封装成对象,并开辟一个新线程执行。
  • 可以将NSOperation对象加入NSOperationQueue队列中进行统一管理,放入队列中的NSOperation将并发执行。
  • 使用NSOperation需要子类化,并重写main方法,加入自定义操作。
  • NSOperation提供了子类来更加方便的初始化一个NSOperation对象:NSBlockOperation、NSInvocationOperation。




NSBlockOperation:

   

NSOperationQueue * queue = [[NSOperationQueuealloc] init];

    NSBlockOperation *blockOperation = [NSBlockOperationblockOperationWithBlock:^{
    //开辟线程做什么
        sleep(5);
    }];
  
    //线程结束后做什么
    [blockOperation setCompletionBlock:^{

        //要做的事情是刷新UI,所以放在主线程中
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.label1.text =@"Good";
                });

    }];

    [queue addOperation:blockOperation];





NSInvocationOperation:

 


NSOperationQueue *queue = [[NSOperationQueuealloc]init];
    NSInvocationOperation *operation = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(sendWords)object:nil];
    [queue addOperation:operation];
 

-(void)sendWords
{
    sleep(3);
    dispatch_async(dispatch_get_main_queue(), ^{
      self.label1.text =@"Good";
    });
}


NSThread:


  • NSThread可以简单开辟一个线程处理需要放到后台的操作。
  • NSThread 比其他两个轻量级。




 

//类方法直接调用sendWords
    [NSThreaddetachNewThreadSelector:@selector(sendWords)toTarget:selfwithObject:nil];
    
    //对象方法,有点是可以设置对象相关参数, 但是需要手动start
    NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(sendWords)object:nil];
    thread.name =@"test";
    [thread start];



注释:


  • 同步执行:只要是同步执行的任务,都会在当前线程执行,不会另开线程。如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行
• <code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">dispatch_sync</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">dispatch_queue_t</span> queue, <<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#^(void)block#>)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"></ul>
  • 异步执行:只要是异步执行的任务,都会另开线程,在别的线程执行。如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。
• <code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">dispatch_async</span>(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">dispatch_queue_t</span> queue, <<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#^(void)block#>)</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"></ul>

队列

  • 队列用于存放任务。一共有三种队列, 串行队列、并行队列和主队列。
  • 主队列:dispatch_get_main_queue()
  • 并行队列:dispatch_get_global_queue(long identifier, unsigned long flags)
  • 串行队列:dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)