多线程编程(一)NSThread
在iOS中每个进程启动后都会建立一个主线程(UI线程),这个线程是其他线程的父线程。由于在iOS中除了主线程,其他子线程是独立于Cocoa Touch的,所以只有主线程可以更新UI界面(新版iOS中,使用其他线程更新UI可能也能成功,但是不推荐)。iOS中多线程使用并不复杂,关键是如何控制好各个线程的执行顺序、处理好资源竞争问题。
多线程开发中,需要明白一点,cpu在同一时间内,只能处理一件事情,多线程开发,只是cpu在各个线程之间来回穿梭调度,并不是cpu能够同时执行多个任务,这一需要明确,本篇博客主要讲一下NSThread
一 NSThread的创建有三种方式
//第一种 先创建 再启动 注意 object参数 如果down方法需要参数 就在object这里把参数传递给down方法
NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(down) object:nil];
[thread start];
//第二种 创建 不用启动
[self performSelectorInBackground:@selector(down) withObject:nil];
//第三种 创建 不用启动
[NSThread detachNewThreadSelector:@selector(down) toTarget:self withObject:nil];
把比较耗时的操作放在down方法中,但是不要把UI的更新放在down方法中。
取消线程 [thread cancel];线程执行完操作后 会自动销毁,也就是说 一个线程只能处理一个任务
二 线程之间的通信 ,比如在子线程中下载一张图片,下载完要回到主线程刷新UI;
[self performSelectorOnMainThread:@selector(update:) withObject:img waitUntilDone:YES];
这句代码中的withObject:后面的参数img就是下载的图片,然后在update:方法中 给imgView赋值,
这句代码还有一种表达方式
[self performSelector:@selector(update:) onThread:[NSThread mainThread] withObject:img waitUntilDone:YES];
其实这里还有一种比较简单的方法 不用写update方法了 既然给imgView赋值 直接这样写
[self.myImgView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:img waitUntilDone:YES];
三 线程间的安全问题
如果我们的多个线程对同一个资源同时访问,可能就会产生问题,比如我们的卖票问题,比如开了三个线程卖票,共有10张票,线程一访问时是10张,当线程一访问完后,线程二又马上来访问,线程二访问时还是10张,线程二访问完后,线程一卖了一张票,此时线程一返回给服务器的值是10-1 = 9张票,此时线程二也卖了一张,线程二返回的肯定也是10-1=9张,这样肯定是有问题的,为了避免这种情况,此时我们要为共同访问的资源加锁,还是直接上代码。
self.thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread1.name = @"窗口1";
self.thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread2.name = @"窗口2";
self.thread3 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread3.name = @"窗口3";
[self.thread1 start];
[self.thread2 start];
[self.thread3 start];
@synchronized(self){
int count = self.leftTicketCount;
if (count > 0) {
self.leftTicketCount = count - 1;
NSLog(@"%@卖了1张票,还剩%d张票",[NSThread currentThread].name,self.leftTicketCount);
}else{
return;
}
}
其实@synchronized()就是加锁,后面小括号里面就是锁对象, 锁对象的可以是任意的对象,可以直接用self,注意 锁要用一个 不能每次创建一个 那样和没加锁是一样的效果,
NSThread的大体用法就这些,现在已经不是太常用NSThread 了 主要是用GCD 和NSOperation 另外还有一种Pthread 几乎不用,有兴趣的可以了解下,GCD和NSOperation会在后面的章节写下,哪里有不对的地方,欢迎大家评批指正。