您的位置:首页 > 其它

GCD常用基本API介绍以及创建单例的两种方式

2016-12-21 14:17 531 查看
GDC的介绍有另外一篇博客专门写了下,需要看的可以点击以下传送门GCD线程死锁解锁案例分析,这里主要记录下基本的API使用以及两种单例的创建方式

1.GCD同步异步并发串行排列组合的集中基本形式

/*
*  异步串行   --->       不阻塞当前线程,会开多一条线程,在这个线程中是串行执行的
*/
- (void)asynchSerial
{
// 全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 自定义并发队列
dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_SERIAL);

dispatch_async(queue1, ^{
NSLog(@"------1,%@",[NSThread currentThread]);
});

dispatch_async(queue1, ^{
NSLog(@"------2,%@",[NSThread currentThread]);
});

dispatch_async(queue1, ^{
NSLog(@"------3,%@",[NSThread currentThread]);
});
NSLog(@"asynchSerial------end");
//    2016-12-21 09:34:16.222 GCDBasicAPI[1137:38266] asynchSerial------end
//    2016-12-21 09:34:16.222 GCDBasicAPI[1137:38300] ------1,<NSThread: 0x60000007a640>{number = 3, name = (null)}
//    2016-12-21 09:34:16.223 GCDBasicAPI[1137:38300] ------2,<NSThread: 0x60000007a640>{number = 3, name = (null)}
//    2016-12-21 09:34:16.223 GCDBasicAPI[1137:38300] ------3,<NSThread: 0x60000007a640>{number = 3, name = (null)}

}

/*
*  同步串行   --->       阻塞当前线程,不开多条线程,在当前线程执行,顺序执行
*/
- (void)synchSerial
{
// 全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 自定义并发队列
dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_SERIAL);

dispatch_sync(queue1, ^{
NSLog(@"------1,%@",[NSThread currentThread]);
});

dispatch_sync(queue1, ^{
NSLog(@"------2,%@",[NSThread currentThread]);
});

dispatch_sync(queue1, ^{
NSLog(@"------3,%@",[NSThread currentThread]);
});
NSLog(@"synchSerial------end");
//    2016-12-21 09:32:25.878 GCDBasicAPI[1117:36348] ------1,<NSThread: 0x600000075700>{number = 1, name = main}
//    2016-12-21 09:32:25.878 GCDBasicAPI[1117:36348] ------2,<NSThread: 0x600000075700>{number = 1, name = main}
//    2016-12-21 09:32:25.879 GCDBasicAPI[1117:36348] ------3,<NSThread: 0x600000075700>{number = 1, name = main}
//    2016-12-21 09:32:25.879 GCDBasicAPI[1117:36348] synchSerial------end

}

/*
*  同步并发   --->       阻塞当前线程,不开多条线程,在当前线程执行,顺序执行
*/
- (void)synchConcurrent
{
// 全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 自定义并发队列
dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_CONCURRENT);

dispatch_sync(queue1, ^{
NSLog(@"------1,%@",[NSThread currentThread]);
});

dispatch_sync(queue1, ^{
NSLog(@"------2,%@",[NSThread currentThread]);
});

dispatch_sync(queue1, ^{
NSLog(@"------3,%@",[NSThread currentThread]);
});
NSLog(@"synchConcurrent------end");
//    2016-12-21 09:29:47.575 GCDBasicAPI[1071:33607] ------1,<NSThread: 0x60000006b900>{number = 1, name = main}
//    2016-12-21 09:29:47.575 GCDBasicAPI[1071:33607] ------2,<NSThread: 0x60000006b900>{number = 1, name = main}
//    2016-12-21 09:29:47.576 GCDBasicAPI[1071:33607] ------3,<NSThread: 0x60000006b900>{number = 1, name = main}
//    2016-12-21 09:29:47.576 GCDBasicAPI[1071:33607] synchConcurrent------end

}

/*
*  异步并发   --->       不阻塞当前线程,可以开多条线程,并发执行,顺序不一定
*/
- (void)asynchConcurrent
{
// 全局并发队列
//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 自定义并发队列
dispatch_queue_t queue1 = dispatch_queue_create("COM.MKJ.COM", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue1, ^{
NSLog(@"------1,%@",[NSThread currentThread]);
});

dispatch_async(queue1, ^{
NSLog(@"------2,%@",[NSThread currentThread]);
});

dispatch_async(queue1, ^{
NSLog(@"------3,%@",[NSThread currentThread]);
});
NSLog(@"asynchConcurrent------end");
//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32223] asynchConcurrent------end
//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32292] ------1,<NSThread: 0x60800026e180>{number = 3, name = (null)}
//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32293] ------3,<NSThread: 0x60800026fbc0>{number = 5, name = (null)}
//    2016-12-21 09:28:23.895 GCDBasicAPI[1050:32295] ------2,<NSThread: 0x60000026e0c0>{number = 4, name = (null)}

}


简单概括如下:

项目同步(sync)异步(async)
串行当前线程,顺序执行另一个线程,顺序执行
并发当前线程,顺序执行另一个线程,同时执行
可以看出同步和异步就是开线程的能力,同步执行必然一个个顺序执行在当前线程,而异步执行可以根据队列不同来确定顺序还是同步并发执行

2.最基本的线程间通讯方式

// 不阻塞当前线程,后台拉取图片资源
dispatch_async(dispatch_get_global_queue(0, 0), ^{

NSURL *url = [NSURL URLWithString:@"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRCfHVwGXGvrpCBplQieSKsLgfBULL8ZZXSzosPFdoZsvjDlqnOrKK_w58"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
NSLog(@"获取资源%@",[NSThread currentThread]);
// 下载完之后回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
NSLog(@"加载资源%@",[NSThread currentThread]);
});
});

//    2016-12-21 09:43:51.675 GCDBasicAPI[1237:45972] 获取资源<NSThread: 0x6000002742c0>{number = 3, name = (null)}
//    2016-12-21 09:43:51.676 GCDBasicAPI[1237:45929] 加载资源<NSThread: 0x60000007b680>{number = 1, name = main}


3.其他Barrier,apply,after,Group等常用API

dispatch_barrier_async

/*
*  barrier函数可以阻塞任务,执行到他这里,要等之前的任务执行完才能执行之后的任务
*/
- (void)barrier
{
dispatch_queue_t queue = dispatch_queue_create("com.mkj.hehe", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"--------1,%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i < 10; i ++)
{
NSLog(@"--------2%ld,%@",i,[NSThread currentThread]);
}

});
dispatch_barrier_async(queue, ^{
NSLog(@"--------3,%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"--------4,%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"--------5,%@",[NSThread currentThread]);
});
//    2016-12-21 09:58:09.231 GCDBasicAPI[1392:57437] --------1,<NSThread: 0x60000007f400>{number = 5, name = (null)}
//    2016-12-21 09:58:09.231 GCDBasicAPI[1392:57807] --------20,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.232 GCDBasicAPI[1392:57807] --------21,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------22,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------23,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------24,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------25,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.233 GCDBasicAPI[1392:57807] --------26,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------27,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------28,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------29,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.234 GCDBasicAPI[1392:57807] --------3,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.235 GCDBasicAPI[1392:57807] --------4,<NSThread: 0x60000007e780>{number = 7, name = (null)}
//    2016-12-21 09:58:09.235 GCDBasicAPI[1392:57437] --------5,<NSThread: 0x60000007f400>{number = 5, name = (null)}
}


dispatch_apply

/*
*  apply 无序快速遍历,可以用于文件移动等需求
*/
- (void)apply
{
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%ld,%@",index,[NSThread currentThread]);
});
//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63041] 0,<NSThread: 0x600000069940>{number = 1, name = main}
//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63172] 2,<NSThread: 0x60800007a940>{number = 7, name = (null)}
//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63845] 1,<NSThread: 0x60800007a8c0>{number = 6, name = (null)}
//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63873] 3,<NSThread: 0x60800007ab00>{number = 8, name = (null)}
//    2016-12-21 10:04:01.487 GCDBasicAPI[1485:63041] 4,<NSThread: 0x600000069940>{number = 1, name = main}
//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63172] 5,<NSThread: 0x60800007a940>{number = 7, name = (null)}
//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63845] 6,<NSThread: 0x60800007a8c0>{number = 6, name = (null)}
//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63873] 7,<NSThread: 0x60800007ab00>{number = 8, name = (null)}
//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63041] 8,<NSThread: 0x600000069940>{number = 1, name = main}
//    2016-12-21 10:04:01.488 GCDBasicAPI[1485:63172] 9,<NSThread: 0x60800007a940>{number = 7, name = (null)}
}


dispatch_after

/*
*  延时执行
*/
- (void)delay
{
// 方法1
NSLog(@"开始了");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"我才开始");
});
// 方法2
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];
}

- (void)run
{
NSLog(@"run");
}


dispatch_group_async

/*
*  线程组  实现多个请求完成之后同时刷新UI的问题
*  把多个任务加入到队列里面,最后都完成之后会调用Notify的方法进行通知,最终刷新UI
*/

- (void)group
{
// 并发队列
dispatch_queue_t queue = dispatch_queue_create("com.mkj.hh", DISPATCH_QUEUE_CONCURRENT);
// 线程组
dispatch_group_t group = dispatch_group_create();
// 任务1加入组
dispatch_group_async(group, queue, ^{

NSURL *url = [NSURL URLWithString:@"https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQxex7CvJ0pArQ8NHwXMaZ8fSt3ALAZBlljTQVlDsh6AIegeMjWWMoSVtej"];
NSData *data = [NSData dataWithContentsOfURL:url];
self.image1 = [UIImage imageWithData:data];
});

// 任务2加入组
dispatch_group_async(group, queue, ^{
// 这里可以一样是耗时的网络请求,暂时处理成本地的
self.image2 = [UIImage imageNamed:@"Play"];
});
// 任务完成之后统一通知
dispatch_group_notify(group, queue, ^{

// 这里的queue如果是mainQueue的话就可以直接回到主线程操作需要的UI
// 现在还是在并发队列里面  进行图片合成  还是放在子线程
UIGraphicsBeginImageContext(CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.width));
[self.image1 drawInRect:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.width)];
[self.image2 drawInRect:CGRectMake([UIScreen mainScreen].bounds.size.width/2, [UIScreen mainScreen].bounds.size.width/2, 30, 40)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// 回到主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});

});
}




4.两种方式实现单例

自己加锁实现

static id obj;

+ (instancetype)shareInstance
{
@synchronized (self) {
if (!obj) {
obj = [[self alloc] init];
}
}
return obj;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
@synchronized (self) {
if (!obj) {
obj = [super allocWithZone:zone];
}
}
return obj;
}

- (id)copyWithZone:(NSZone *)zone
{
return obj;
}


GCD实现(直接抽成宏)

#define MKJSingletonH + (instancetype)shareManager;
#define MKJSinletonM \
static id obj; \
\
+ (instancetype)shareManager \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
obj = [[self alloc] init]; \
}); \
return obj; \
} \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
obj = [super allocWithZone:zone]; \
}); \
return obj; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return obj; \
}


抽成宏之后可以直接进行调用就OK

@interface ManagerHelper : NSObject
MKJSingletonH
@end

@implementation ManagerHelper
MKJSinletonM
@end


注:这里为什么需要用Static进行修饰,static保证只有本文件才能访问,这样就能形成单例,但是如果不用static修饰,外部也一样能访问,这个时候外部如果置为nil之后,这个对象就不存在了,再也不会创建了,dispatch_once只会执行一次,这样肯定不对的

非常简单的介绍,这里有个Demo,需要的朋友可以下载看看基础用法先,文章头部有介绍GCD死锁解锁的案例文章,需要的也可以看看

本文Demo传送门

NSOperation用法和GCD之间的关系
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息