博客> 多线程详解
多线程详解
1小时前 评论:0 阅读:285 不醉free
ios GCD 多线程 NSOperation

/** 无论使用哪种多线程技术都可以使用 [NSThread currentThread]跟踪查看当前执行所在的线程情况。 num = 1表示在主线程上执行的任务

================================================================

  1. NSObject多线程技术

    1> 使用performSelectorInBackground可以开启后台线程,执行selector选择器选择的方法 2> 使用performSelectorOnMainThread可以重新回到主线程执行任务,通常用于后台线程更新界面UI时使用 3> [NSThread sleepForTimeInterval:1.0f]; 让当前线程休眠,通常在程序开发中,用于模拟耗时操作,以便跟踪不同的并发执行情况!

    但是:在程序发布时,千万不要保留此方法!不要把测试中的代码交给客户,否则会造成不好的用户体验。

    提示:使用performSelectorInBackground也可以直接修改UI,但是强烈不建议使用。

    注意:在使用NSThread或者NSObject的线程方法时,一定要使用自动释放池,否则容易出现内存泄露。 代码演示: (1)NSObject开辟子线程 [self performSelectorInBackground:@selector(bigDemo) withObject:nil]; (2)用NSThread方法开辟子线程 2.1// 类方法新建一个线程,调用@selector方法 [NSThread detachNewThreadSelector:@selector(bigDemo) toTarget:self withObject:nil]; 2.2 // 成员方法 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(bigDemo) object:nil]; // 启动start线程 [thread start]; 被子线程调用的方法:

    • (void)bigDemo { // 自动释放池 // 负责其他线程上的内存管理,在使用NSThread或者NSObject的线程方法时,一定要使用自动释放池 // 否则容易出现内存泄露。 @autoreleasepool {

      NSLog(@"%@", [NSThread currentThread]); // 模拟网络下载延时,睡眠1秒,通常是在开发中测试使用。 [NSThread sleepForTimeInterval:1.0f];

      // 强烈不建议直接在后台线程更新界面UI! // 模拟获取到下载的图像 UIImage *image = [UIImage imageNamed:@"头像1"];

      // 在主线程更新图像 // 使用self调用updateImage方法在主线程更新图像 [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:YES]; // 使用imageView的setImage方法在主线程更新图像 [_imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

    } } 被主线程调用的方法:

    • (void)updateImage:(UIImage *)image { NSLog(@"更新图像-> %@", [NSThread currentThread]);

    _imageView.image = image; }



    1、NSOperation & NSOperationQueue基于OC框架写的 • NSOperation的两个⼦子类 NSInvocationOperation NSBlockOperation • ⼯工作原理: ⽤用NSOperation封装要执⾏行的操作 将创建好的NSOperation对象放NSOperationQueue中 启动OperationQueue开始新的线程执⾏行队列中的操作

1.1、#pragma mark invocation

  • (IBAction)operationDemo1 { NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(opAction) object:nil];

    // 如果使用start,会在当前线程启动操作 // [op1 start];

    // 1. 一旦将操作添加到操作队列,操作就会启动 [_queue addOperation:op1]; }

    pragma mark - NSOperation演练

  • (void)opAction { NSLog(@"%@", [NSThread currentThread]);

    // 模拟网络加载延时 [NSThread sleepForTimeInterval:1.0f];

    // 模拟获取到图像 UIImage *image = [UIImage imageNamed:@"头像1"];

    // 设置图像,在主线程队列中设置 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ _imageView.image = image; }]; } 、、、、、、、、、、、、、、、、、、、 1.2#pragma mark blockOperation

  • (IBAction)operationDemo2 { // 用block的最大好处,可以将一组相关的操作,顺序写在一起,便于调试以及代码编写 [_queue addOperationWithBlock:^{ NSLog(@"%@", [NSThread currentThread]);

    // 模拟延时
    [NSThread sleepForTimeInterval:1.0f];
    
    // 模拟获取到图像
    UIImage *image = [UIImage imageNamed:@"头像1"];
    
    // 设置图像,在主线程队列中设置
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        _imageView.image = image;
    }];

    }]; } //invocation和blockOperation区别就是一个是用方法调用,一个是代码块调用

    2 、NSOperation对象放NSOperationQueue牛逼之处

    pragma mark 依赖关系,可以使子线程按顺序执行

  • (IBAction)operationDemo3:(id)sender { _queue=[[NSOperationQueue alloc]init]; // 1. 下载 NSBlockOperation op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下载 %@" , [NSThread currentThread]); }]; // 2. 滤镜 NSBlockOperation op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"滤镜 %@" , [NSThread currentThread]); }]; // 3. 显示 NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"更新UI %@" , [NSThread currentThread]); }];

    // 添加操作之间的依赖关系,所谓“依赖”关系,就是等待前一个任务完成后,后一个任务才能启动 // 依赖关系可以跨线程队列实现 [op2 addDependency:op1]; [op3 addDependency:op2]; // 提示:在指定依赖关系时,注意不要循环依赖,否则不工作。 //[op1 addDependency:op3];

    [_queue addOperation:op1]; [_queue addOperation:op2]; [[NSOperationQueue mainQueue] addOperation:op3]; } 2.1可以设置最大并发的线程数量,这是NSOperation独有功能

  • (IBAction)operationDemo4 { // 控制同时最大并发的线程数量 [_queue setMaxConcurrentOperationCount:2];

    for (NSInteger i = 0; i < 200 xss=removed> 要使用GCD,所有的方法都是dispatch开头的 2> 名词解释 global 全局 queue 队列 async 异步: 执行控制不住先后顺序 sync 同步: 主要用来控制方法的被调用的顺序

    3> 要执行异步的任务,就在全局队列中执行即可 dispatch_async 异步执行控制不住先后顺序

    4> 关于GCD的队列 全局队列 dispatch_get_global_queue 参数:优先级 DISPATCH_QUEUE_PRIORITY_DEFAULT 始终是 0 串行队列 主队列

    5> 异步和同步于方法名无关,与运行所在的队列有关! 提示:要熟悉队列于同步、异步的运行节奏,一定需要自己编写代码测试!

    同步主要用来控制方法的被调用的顺序

    */ // 1. 队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2. 将任务异步(并发)执行 dispatch_sync(queue, ^{ NSLog(@"a->%@", [NSThread currentThread]);//同步在哪个线程,它执行的方法就在哪个线程 }); dispatch_async(queue, ^{ NSLog(@"b->%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ dispatch_sync(queue, ^{ NSLog(@"我哦我哦我->%@", [NSThread currentThread]); }); //"我哦我哦我"所在的线程就是这个子线程“不不不不不不不不不”所在的线程 NSLog(@"不不不不不不不不不->%@", [NSThread currentThread]); }); //从GCD回到主线程的时候必须是异步的 dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"main - > %@", [NSThread currentThread]); });//dispatch_sync方法不能在主队列中调用,因为这会无限期的阻止线程并会导致你的应用死锁。所有通过GCD提交到主队列的任务必须是异步的。

} 1.1#pragma mark 串行队列,里面的操作按顺序执行 create方法,获得的是自己新建的线程,所以create需要我们释放线程(如果是手动管理内存的话) //dispatch_queue_t用来引导队列变量 //createQueue 就是一个队列变量 //dispatch_queue_create是手动创建队列的方法,两个参数,第一个参数是这个队列的名,第二个参数如果写DISPATCH_QUEUE_SERIAL或者NULL表示这是一个顺序的队列,这个队列里的方法顺序执行。如果是DISPATCH_QUEUE_CONCURRENT,表示这是一个并行的队列,则这个队列里的方法同时执行

   //create出来的默认为default优先级

//用完之后,要释放
//dispatch_release(createQueue);

-(void)gcdDemo2 { //串行队列自行创建,不能get dispatch_queue_t queue=dispatch_queue_create("Myqueue",NULL); dispatch_async(queue, ^{ NSLog(@"a->%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"b->%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"c->%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"d->%@", [NSThread currentThread]); }); //从GCD回到主线程的时候必须是异步的 dispatch_async(queue, ^{ //必须将这个回到主线程的方法,放在这个队列中的一个请求方法,才会按照顺序执行 dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"不不不不不不不不不 - > %@", [NSThread currentThread]); });//dispatch_sync方法不能在主队列中调用,因为这会无限期的阻止线程并会导致你的应用死锁。所有通过GCD提交到主队列的任务必须是异步的。

});

} 全局队列和并发队列的区别:     1,全局队列没有名字,但是并发队列有名字。有名字可以便于查看系统日志     2,全局队列是所有应用程序共享的。     3,在mrc的时候,全局队列不用手动释放,但是并发队列需要。     

收藏
0
sina weixin mail 回到顶部