面试官:你给我讲讲多线程吧。
我:多线程,就是多线程呗。。。
要是都这么回答,还有多少人要你。
=====================================================
首先分析多线程的使用环境:
多线程处理包括Core Data的多线程访问,UI的并行绘制,异步网络请求以及一些在运行态内存吃紧的情况下处理大文件的方案等。
其次,分别举例说明iOS提供的多线程的实现方法
iOS中提供了以下集中中多线程的实现方式
1.NSOBjcet实现
// 最简单的多线程 执行方式 // 参数1:需要在后台(子线程)执行方法 // 参数2:给这个方法传参 [self performSelectorInBackground:@selector(btnUpClicked:)withObject:nil];
2.NSThread实现
// 优点:在所有的多线程实现方式中 最轻量级 // 可以按照需求 任意控制thread对象 即:线程的加锁等操作 // 缺点:控制太繁琐 不能自己控制线程安全 // NSThread 的一个对象 就代表一个线程 NSThread *thread = [[NSThread alloc]initWithTarget:selfselector:@selector(btnUpClicked:)object:nil]; [thread start]; [thread release];
3.NSOperation实现
// NSOperation代表一个任务 自己不能实现多线程 // NSOperation是一个抽象类 不能直接使用 需要创建一个子类去编写实现的内容 // 任务开始 会在当前线程执行任务(main方法中的代码) MyOperation *operation = [[MyOperation alloc] init]; [operation start]; [operation release]; // 系统已经写好了两个类 可以直接使用 // NSInvocationOperation *invocation = [[NSInvocationOperation alloc] initWithTarget:<#(id)#> selector:<#(SEL)#> object:<#(id)#>] NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{ // 填写你要执行的任务内容 }];
@implementation MyOperation - (void)main { // operation在main方法中写要执行的任务 static int count = 0 ; for (int i = 0 ; i < 600000000; i ++) { count ++; } NSLog(@"%d", count); // 判断当前任务是否为主线程 0为不是 1为是 BOOL b = [NSThread isMainThread]; NSLog(@"%d", b); NSThread *thread = [NSThread currentThread]; NSLog(@"当前线程为:%@", thread); } @end
4.NSOperationQueue
// 任务队列(NSOperationQueue) 内部管理一些列的线程 MyOperation *op1 = [[MyOperation alloc] init]; MyOperation *op2 = [[MyOperation alloc] init]; MyOperation *op3 = [[MyOperation alloc] init]; MyOperation *op4 = [[MyOperation alloc] init]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 设置最大并发数 [queue setMaxConcurrentOperationCount:2]; [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3]; [queue addOperation:op4]; // 优点:能够自己管理 线程安全 能够合理的安排线程 降低系统的开销 提高对线程的利用率 // 缺点:可读性差 写起来比较繁琐
5.GCD
// GCD 是基于队列的 多线程实现方式 // 队列的类型 // 1.并行: 多个任务同时执行 Concurrent // 2.串行: 依次执行任务(同一事件只执行一个任务) Serial // 自己创建一个队列 // 参数1:给队列起个名字 // 参数2:选择队列的类型 DISPATCH_QUEUE_CONCURRENT(串行) dispatch_queue_attr_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT); // 使用队列 // 参数1: 在哪个队列执行代码 // 参数2: 要执行的代码 dispatch_async(queue, ^{ [self btnUpClicked:nil]; });
高级用法:
// 系统定义了5个队列 // 1. 一个串行队列 主队列作用 : 管理主线程的相关事务 // 获得主队列 dispatch_queue_t mainQueue = dispatch_get_main_queue(); // 在主队列执行任务 // dispatch_async(mainQueue, ^{ // [self btnUpClicked:nil]; // }); // 2. 4个并行队列 (并行队列) // 参数1: 选择队列的优先级 // 参数2: 给未来使用 一般填0 dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // dispatch_async(globalQueue, ^{ // [self btnUpClicked:nil]; // }); // 高端使用 // 1.全局队列获取数据 回到主队列将数据加载到视图上 // dispatch_async(globalQueue, ^{ // // // 全局队列(子线程)获取数据 // NSString *str = @"htt://www.baidu.com"; // NSURL *url = [NSURL URLWithString:str]; // // NSData *data = [NSData dataWithContentsOfURL:url]; // UIImage *image = [UIImage imageWithData:data]; // // // 返回主线程 加载UI/更新UI // dispatch_async(mainQueue, ^{ // // UIImageView *imageView = [[UIImageView alloc] init]; // // 给视图赋值 // imageView.image = image; // // }); // }); // 2.一段代码只执行依次 // 大部分的时候 都在单例方法中使用 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"只执行依次"); }); // 3.一段代码执行多次 (全局队列有效) // 参数1: 执行多少次 // 参数2: 在哪个队列有效 // 参数3: 要执行的内容 dispatch_apply(4, globalQueue, ^(size_t a) { NSLog(@"%zu", a); }); // 4.定时 // 参数1: 间隔几秒 // 参数2: 执行的内容 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"====="); });
强烈建议用GCD去吓唬人。这可不是我说的,是他们总结的,反正好用就是个,尤其是遇到面试官不是iOS开发的。。。左拉有扯地拉他回GCD。一句话GCD万岁~