IOS多线程之(GCD)

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法

1.常用的方法dispatch_async 耗时的操作

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// 耗时的操作 

dispatch_async(dispatch_get_main_queue(), ^{ 

    // 更新界面 

}); 

});

1.Dispatch Group的使用

  • (void)downloadImages {

    并行执行

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

      // 下载第一张图片  
    
      NSString *url1 = @"<http://car0.autoimg.cn/upload/spec/9579/u_20120110174805627264.jpg>";  
    
      UIImage *image1 = [self imageWithURLString:url1];  
    
      // 下载第二张图片  
    
      NSString *url2 = @"<http://hiphotos.baidu.com/lvpics/pic/item/3a86813d1fa41768bba16746.jpg>";  
    
      UIImage *image2 = [self imageWithURLString:url2];  
    
      // 回到主线程显示图片  
    
      dispatch_async(dispatch_get_main_queue(), ^{  
    
          self.imageView1.image = image1;  
    
          self.imageView2.image = image2;  
    
      });  

    });

}

两张图片的下载过程并不需要按顺序执行,并发执行它们可以提高执行速度

+(void)dispatch{

//得到队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{

    // 耗时的操作

    //  创建一个组

    dispatch_group_t group = dispatch_group_create();

    // 创建一组任务

    dispatch_group_async(group, queue, ^{

        NSLog(@"并行执行线程一");

    });

    // 创建二组任

    dispatch_group_async(group, queue, ^{

        NSLog(@"并行执行线程二");

    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

        // 更新界面

        NSLog(@"主线程更新界面");

    });

});

}

/// 另一种写法

  • (void)requestDatasGroup {

    // 创建调度组

    dispatch_group_t group = dispatch_group_create();

    // 创建队列

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

      NSLog(@"接口 A 数据请求完成");
    
      dispatch_group_leave(group);

    });

    dispatch_group_enter(group);

    dispatch_async(queue, ^{

      NSLog(@"接口 B 数据请求完成");
    
      dispatch_group_leave(group);

    });

    NSLog(@”我是最开始执行的,异步操作里的打印是后执行的”);

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{

      NSLog(@"接口 A 和接口 B 的数据请求都已经完毕!, 开始合并两个接口的数据");

    });

}

3、dispatch_barrier_async的使用

顺序执行

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行

例子代码如下

dispatch_queue_t queue = dispatch_queue_create(“gcdtest.rongfzh.yc”, DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:2]; 

NSLog(@"dispatch_async1"); 

});

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:4]; 

NSLog(@"dispatch_async2"); 

});

dispatch_barrier_async(queue, ^{

NSLog(@"dispatch_barrier_async"); 

[NSThread sleepForTimeInterval:4]; 

});

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:1]; 

NSLog(@"dispatch_async3"); 

});

打印结果:

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async

2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

4、dispatch_apply

执行某个代码片段N次。

dispatch_apply(5, globalQ, ^(size_t index) {

// 执行5次

});

5,gcd 延时操作

dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0/延迟执行时间/ * NSEC_PER_SEC));

    dispatch_after(delayTime, dispatch_get_main_queue(), ^{

        [self reciveNotification:userInfo];

    });

其他方法

#pragma mark 第一种解决县城的问题的方法,nsobject提供的方法

-(void)NSObjectThread:(UIButton *)button{

[self performSelectorInBackground:@selector(click:) withObject:button];

 //优点:写法特别简单.能快速开辟一个临时线程

 //缺点:不能保证线程使用时数据的绝对安全

}

#pragma mark 第二种方式

-(void)NSThreadAction:(UIButton *)button{

//NSThread 本身就是一个线程类,它可以控制线程休眠或者创建..

//当前的主线程

NSLog(@"%@",[NSThread currentThread]);

//主线程休眠3s

// [NSThread sleepForTimeInterval:3];

// NSLog(@”0002112121”);

//如果用创建对象,创建出来的就是新的线程..

NSThread *thread=[[[NSThread alloc] initWithTarget:self selector:@selector(click:) object:nil] autorelease];

//可以给新的线程对象起名

thread.name=@"kitty";

//启动子线程.

[thread start];

//优点:可以直接通过创建的方式来控制线程.

//缺点:什么都需要手动设置,包括名,开始.太麻烦..

}

#pragma mark 第三种 NSOperation 任务

-(void)operationQueue:(UIButton *)button{

//队列和任务一起配合使用解决多线程的问题..

//队列:队列中通过一个线程池来管理所有闲置的线程,这样就可以提高线程的重用率,避免重复的创建线程,,整合资源

//优点:内部不需要关心线程的安全问题,用起来相对简单//

//缺点:效率稍微优点低...

NSOperationQueue *queue=[[NSOperationQueue alloc] init];

//设置最大并发数..

[queue setMaxConcurrentOperationCount:2];

MyOperation *op1=[[MyOperation alloc] init];

MyOperation *op2=[[MyOperation alloc] init];

MyOperation *op3=[[MyOperation alloc] init];

MyOperation *op4=[[MyOperation alloc] init];

MyOperation *op5=[[MyOperation alloc] init];

//把任务加到队列里

 [queue addOperation:op1];

 [queue addOperation:op2];

 [queue addOperation:op3];

 [queue addOperation:op4];

 [queue addOperation:op5];

}

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

MyOperation 继承于 NSOperation

@implementation MyOperation

-(void)main{

// 要执行的操作。。

}

@end

//利用GCD的dispatch_once的方法实现单利模式

  • (instancetype)defaultManager {

staticMusicPlayerViewController *_instance =nil;

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

_instance = [[selfalloc] init];

});

return_instance;

}

6.后台运行

GCD的另一个用处是可以让程序在后台较长久的运行。在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。

// AppDelegate.h文件

@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;

// AppDelegate.m文件

  • (void)applicationDidEnterBackground:(UIApplication *)application

{

[self beingBackgroundUpdateTask];

// 在这里加上你需要长久运行的代码

[self endBackgroundUpdateTask];

}

  • (void)beingBackgroundUpdateTask

{

self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

    [self endBackgroundUpdateTask];

}];

}

  • (void)endBackgroundUpdateTask

{

[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];

self.backgroundUpdateTask = UIBackgroundTaskInvalid;

}

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!