进程:内存里的一个程序就是一个进程,运行起来的程序就是一个进程,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,每个进程均运行在其专用且受保护的内存空间内,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。
线程:线程是指进程内的一个执行单元,也是进程内的可调度实体,一个应用至少有一个线程(主线程)(IOS中UI主线程)
iOS有三种多线程编程的技术,分别是:
(一)NSThread
(二)Cocoa NSOperation
(三)GCD(全称:Grand Central Dispatch)
这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
NSThread#
- 优点:NSThread 比其他两个轻量级
- 缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
-(void)downloadImage:(NSString *) url{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc] initWithData:data];
if(image == nil){
} else{
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}
- (void)viewDidLoad {
[super viewDidLoad];
// [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:kURL];
[thread start];
}
NSOperation#
使用 NSOperation的方式有两种,一种是用定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。另一种是继承NSOperation。
- (void)viewDidLoad{
[super viewDidLoad];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage:) object:kURL];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
-(void)downloadImage:(NSString *)url{
NSURL *nsUrl = [NSURL URLWithString:url];
NSData *data = [[NSData alloc] initWithContentsOfURL:nsUrl];
UIImage * image = [[UIImage alloc] initWithData:data];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}
GCD#
什么是GCD?
全称是Grand Central Dispatch,纯C语言,提供了非常多强大的函数-
GCD的优势
- 苹果公司为多核的并行运算提出的解决方案
- 自动利用更多的CPU内核(比如双核、四核)
- 自动管理线程的生命周期(创建线程、调度任务、销毁线程)
- 程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码
dispatch_queue_t queue =dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
//1.获取网址字符串
NSString * urlString = @"http://www.bz55.com/uploads/allimg/121230/1-121230094954.jpg";
//2.NSString->NSURL
NSURL * url = [NSURL URLWithString:urlString];
//3.同步下载
NSData * data = [NSData dataWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
dispatch_sync(dispatch_get_main_queue(), ^{
self.view.backgroundColor = [UIColor colorWithPatternImage:image];
});
});
**P.S. **
子线程里面不能更行主线程的UI
只有主线程能够更新UI,其他都不行
子线程没有能力去更新主线程的UI,我们之所以能够看到某些时候更新了的效果,是因为子线程结束,立刻回到了主线程中,主线程更新子线程里面要求的UI,由于子线程结束回到主线程的时间比较短,因此造成了一种误解,以为是子线程更新了UI,实则是UI主线程自己做的
如果在子线程里面直接更新UI, 可能会造成两种错误
a. UI的更新不及时,必须等子线程结束了,主线程才会去更新UI
b. 当子线程还没有结束,主线程中已经将UI元素释放,那么当子线程结束了,回到主线程中,就会去继续更新这个UI元素,可是UI已经没有了,造成内存错误当子线程执行完毕,立刻返回到主线程,如果子线程有需要让主线程做一定的事情,那么主线程会挂起其他的任务,执行这些事情
参考资料
关于iOS多线程,你看我就够了
iOS开发多线程篇—GCD介绍
iOS多线程编程之Grand Central Dispatch(GCD)介绍和使用