Cowboy Tech

GCD编程

串行队列

串行队列一次只执行一个线程,按照添加到队列的顺序依次执行

- (void)viewDidLoad {
[self serailQueue];
}


//串行队列
- (void)serailQueue {

//创建出了队列
GCDQueue *queue = [[GCDQueue alloc]initSerial];

//执行队列中的线程
[queue execute:^{
    NSLog(@"1");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"2");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"3");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"4");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"5");
}];
}

并发队列

并发队列一次可以执行多个线程,线程的执行没有先后顺序

- (void)viewDidLoad {
[self serailQueue];
}

//并发队列,5个线程同时执行
- (void)initConcurrent{

//创建出了队列
GCDQueue *queue = [[GCDQueue alloc]initConcurrent];

//执行队列中的线程
[queue execute:^{
    NSLog(@"1");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"2");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"3");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"4");
}];

//执行队列中的线程
[queue execute:^{
    NSLog(@"5");
}];

}

UI界面所在的线程队列是串行队列

在子线程中处理业务逻辑,在主线程中更新UI

- (void)viewDidLoad {

self.imageView        = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
self.imageView.center = self.view.center;
[self.view addSubview:self.imageView];

[GCDQueue executeInGlobalQueue:^{

    //处理业务逻辑,下载操作

    NSString *netUrlString = @"http://pic.cnitblog.com/avatar/607542/20140226182241.png";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:netUrlString]];
    NSData *picData = [NSURLConnection sendSynchronousRequest:request
                                            returningResponse:nil
                                                        error:nil];


    [GCDQueue executeInMainQueue:^{

        //更新UI
        self.imageView.image = [[UIImage alloc] initWithData:picData];

    }];

}];

}

延时操作

NSThread方式

优点:时间比较精确,而且可以用方法取消。缺点:比较繁琐

- (void)viewDidLoad {

[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

NSLog(@"启动");

//NSThread方式的延时执行操作
[self performSelector:@selector(threadEvent:)
           withObject:self
           afterDelay:2.f];

//取消延时执行操作
[NSObject cancelPreviousPerformRequestsWithTarget:self];

}

- (void)threadEvent:(id)sender{
NSLog(@"线程事件");
}

GCD方式

优点:简单快捷。缺点:时间不够精确,不能取消。

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

NSLog(@"启动");
//GCD方式的延时执行操作
[GCDQueue executeInMainQueue:^{
    NSLog(@"GCD线程事件");
} afterDelaySecs:2.f];

}

GCD线程组(管理线程)

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

//初始化线程组合
GCDGroup *group = [[GCDGroup alloc]init];

//创建一个线程队列
GCDQueue *queue = [[GCDQueue alloc]initConcurrent];

//让线程在group中执行线程1
[queue execute:^{
    sleep(1);
    NSLog(@"线程1执行完毕");
} inGroup:group];

//让线程在group中执行线程2
[queue execute:^{
     sleep(3);
    NSLog(@"线程2执行完毕");
} inGroup:group];

//监听线程组是否执行结束,然后执行线程3
[queue notify:^{
    NSLog(@"线程3执行完毕");
} inGroup:group];
}

定时器

GCD定时器

@interface ViewController ()
@property (nonatomic, strong) GCDTimer *timer;
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.timer = [[GCDTimer alloc] initInQueue:[GCDQueue mainQueue]];
[self.timer event:^{
    NSLog(@"GCD定时器");
} timeInterval:NSEC_PER_SEC];

[self.timer start];
}

@end

NSTimer定时器

仅运行在当前runloop? 不能用于tableView?

@interface ViewController ()
@property (nonatomic,strong)NSTimer *normalTimer;
@end

- (void)viewDidLoad {
[super viewDidLoad];   
 self.normalTimer = [NSTimer scheduledTimerWithTimeInterval:1
                                                    target:self
                                                  selector:@selector(timerEvent)
                                                  userInfo:nil
                                                   repeats:YES];
}

- (void)timerEvent{
NSLog(@"NSTimer定时器");
}    

GCD信号量- 异步线程转换为同步线程

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

//必须线程1先执行完,然后再执行完线程2

//创建信号量, 可以将异步线程转化为同步线程
GCDSemaphore * semaphore = [[GCDSemaphore alloc]init];


//线程1 - 异步
[GCDQueue executeInGlobalQueue:^{
    NSLog(@"线程1");

    //发送信号
    [semaphore signal];

}];

//线程2 - 异步
[GCDQueue executeInGlobalQueue:^{

    //等待信号,这时会堵塞住,不会往下执行,直到接收到信号
    [semaphore wait];

    NSLog(@"线程2");
}];

}

综合使用:采用GCD逐一下载图片

#import "ViewController.h"
#import "GCD.h"

@interface ViewController ()

@property(nonatomic, strong) UIImageView *view1;
@property(nonatomic, strong) UIImageView *view2;
@property(nonatomic, strong) UIImageView *view3;

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

self.view1 = [self createImageViewWithFrame:CGRectMake(0, 0, 100, 100)];
self.view2 = [self createImageViewWithFrame:CGRectMake(100, 0, 100, 100)];
self.view3 = [self createImageViewWithFrame:CGRectMake(200, 0, 100, 100)];

NSString *net1 = @"http://pic.cnitblog.com/avatar/607542/20140226182241.png";
NSString *net2 = @"http://pic.cnitblog.com/avatar/708810/20141230105233.png";
NSString *net3 = @"http://pic.cnitblog.com/avatar/704178/20141216150843.png";

//初始化信号量
GCDSemaphore *semaphore = [[GCDSemaphore alloc]init];


//图片1
[GCDQueue executeInGlobalQueue:^{
    UIImage *image1 = [self accessDataByNetString:net1];

    [GCDQueue executeInMainQueue:^{

        [UIView animateWithDuration:2.f animations:^{
            self.view1.image = image1;
            self.view1.alpha = 1.f;
        } completion:^(BOOL finished) {

            //发送信号
            [semaphore signal];
        }];
    }];
}];

//图片2
[GCDQueue executeInGlobalQueue:^{

    UIImage *image2 = [self accessDataByNetString:net2];

    [semaphore wait];

    [GCDQueue executeInMainQueue:^{

        [UIView animateWithDuration:2.f animations:^{
            self.view2.image = image2;
            self.view2.alpha = 1.f;
        } completion:^(BOOL finished) {

            //发送信号
            [semaphore signal];

        }];
    }];
}];

//图片3
[GCDQueue executeInGlobalQueue:^{

    UIImage *image3 = [self accessDataByNetString:net3];

    [semaphore wait];

    [GCDQueue executeInMainQueue:^{

        [UIView animateWithDuration:2.f animations:^{
            self.view3.image = image3;
            self.view3.alpha = 1.f;
        } completion:^(BOOL finished) {
            //发送信号
            [semaphore signal];            }];
    }];
}];
}

//创建view
- (UIImageView *)createImageViewWithFrame:(CGRect)frame {

UIImageView *imageView = [[UIImageView alloc]initWithFrame:frame];
imageView.alpha = 0.f;
[self.view addSubview:imageView];

return imageView;
}

//获取网络图片
- (UIImage *)accessDataByNetString:(NSString *)string{

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:string]];

NSData *data = [NSURLConnection sendSynchronousRequest:request
                                 returningResponse:nil
                                             error:nil];

return [UIImage imageWithData:data];
}
@end

GCD和NSOperationQueue的区别

  1. GCD是纯C语言的API,NSOperationQueue是基于GCD的OC版本封装
  2. GCD只支持FIFO的队列,NSOperationQueue可以很方便的调整执行顺序,设置最大并发数量
  3. NSOperationQueue可以轻松在Operation间设置依赖关系,而GCD需要写很多的代码才能实现
  4. NSOperatinQueue支持KVO,可以监测operation是否正在执行(isExecuted),是否结束(isFinished),是否取消(isCanceled)
  5. GCD的执行速度比NSOperationQueue快

总结:

  1. 任务之间不太互相依赖:GCD
  2. 任务之间有依赖\或者要监听任务的执行情况:NSOperationQueue