举个例子:在同一个程序里面,存在操作A,操作B。假设操作A耗时5s,操作B耗时0.1s,如果我先触发操作A,接着马上触发操作B,那么操作B的响应必定要在A结束以后才能执行;这样会影响用户体验。为什么会这样那? 因为操作A,B都在同一个线程里面,线程的执行是具有顺序性的,A操作结束,才能进行下一个B操作。 但是A操作耗时较长,用户就需要等待5s后才能看到B操作的响应。为了防止这样的事情发生,我们的方法是另外开辟一个线程。
NSThread
NSOperation
GCD
接下来我用以下例子讲述三种多线程的使用方法:
如下界面两个label, 两个button, 点击A按钮执行操作 : 休眠5s -> 将label1的内容变为"Good" ; 点击B按钮: 将label2的内容直接变为“bad”
如果不使用多线程, 当点击完A之后, 马上点击B, 这个时候你会看到的过程是 A的响应完成之后,才去执行操作B, 使用多线程后, 我们会看到A,B操作互不干扰的执行。
GCD是一种较为底层的多线程实现方式,其原理是将操作封装为block,并加入指定队列中开辟新线程执行。
NSOperation以及NSOperationQueue都是对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对象加入NSOperationQueue队列中进行统一管理,放入队列中的NSOperation将并发执行。
使用NSOperation需要子类化,并重写main方法,加入自定义操作。
NSOperation提供了子类来更加方便的初始化一个NSOperation对象:NSBlockOperation、NSInvocationOperation。
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];
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 比其他两个轻量级。
//类方法直接调用sendWords
[NSThreaddetachNewThreadSelector:@selector(sendWords)toTarget:selfwithObject:nil];
//对象方法,有点是可以设置对象相关参数, 但是需要手动start
NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(sendWords)object:nil];
thread.name =@"test";
[thread start];
注释:
队列用于存放任务。一共有三种队列, 串行队列、并行队列和主队列。
主队列:dispatch_get_main_queue()
并行队列:dispatch_get_global_queue(long identifier, unsigned long flags)
串行队列:dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)