IOS-线程(GCD)
一、GCD的使用
//
// IBController3.m
// IBCoder1
//
// Created by Bowen on 2018/4/25.
// Copyright © 2018年 BowenCoder. All rights reserved.
// #import "IBController3.h" @interface IBController3 () @end /*
进程:执行中的应用程序【一个应用程序可以有很多进程(网游双开),在iOS中一个app只有一个进程。】
资源分配最小单元
线程:进程中的一个执行序列,执行调度的最小单元 线程与进程的区别:
a.地址空间和其它资源:进程间拥有独立内存,进程是资源分配的基本单位;线程隶属于某一进程,且同一进程的各线程间共享内存(资源),线程是cpu调度的基本单位。
b.通信:进程间相互独立,通信困难,常用的方法有:管道,信号,套接字,共享内存,消息队列等;线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
c.调度和切换:线程上下文切换比进程上下文切换要快。进程间切换要保存上下文,加载另一个进程;而线程则共享了进程的上下文环境,切换更快。 一、简介
1.什么是GCD
全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”
纯C语言,提供了非常多强大的函数 2.GCD的优势
GCD是苹果公司为多核的并行运算提出的解决方案
GCD会自动利用更多的CPU内核(比如双核、四核)
GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码 二、任务和队列
1.GCD中有2个核心概念
任务:执行什么操作
队列:用来存放任务 2.GCD的使用就2个步骤
定制任务
确定想做的事情 3.将任务添加到队列中
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循队列的FIFO原则:先进先出,后进后出 三、执行任务
1.GCD中有2个用来执行任务的函数
用同步的方式执行任务
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue:队列
block:任务 2.用异步的方式执行任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block); 3.同步和异步的区别
同步:只能在当前线程中执行任务,不具备开启新线程的能力
异步:可以在新的线程中执行任务,具备开启新线程的能力 四、队列的类型
1.GCD的队列可以分为2大类型
并发队列(Concurrent Dispatch Queue)
可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
并发功能只有在异步(dispatch_async)函数下才有效 2.串行队列(Serial Dispatch Queue)
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务) 五、容易混淆的术语
1.有4个术语比较容易混淆:同步、异步、并发、串行
同步和异步主要影响:能不能开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力 2.并发和串行主要影响:任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务 六、并发队列
1.GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 队列的优先级
unsigned long flags); // 此参数暂时无用,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列 2.全局并发队列的优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 七、串行队列
1.GCD中获得串行有2种途径
使用dispatch_queue_create函数创建串行队列
dispatch_queue_t
dispatch_queue_create(const char *label, // 队列名称
dispatch_queue_attr_t attr); // 队列属性,一般用NULL即可
dispatch_queue_t queue = dispatch_queue_create("cn.itcast.queue", NULL); // 创建
dispatch_release(queue); // 非ARC需要释放手动创建的队列 2.使用主队列(跟主线程相关联的队列)
主队列是GCD自带的一种特殊的串行队列
放在主队列中的任务,都会放到主线程中执行
使用dispatch_get_main_queue()获得主队列
dispatch_queue_t queue = dispatch_get_main_queue(); 八、各种队列的执行效果
注意
使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列 九、线程间通信示例
1.从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
}); 十、延时执行
iOS常见的延时执行有2种方式
调用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后再调用self的run方法 使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后执行这里的代码... 在哪个线程执行,跟队列类型有关 }); 十一、一次性代码
使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
}); 十二、队列组
1.有这么1种需求
首先:分别异步执行2个耗时的操作
其次:等2个异步操作都执行完毕后,再回到主线程执行操作 2.如果想要快速高效地实现上述需求,可以考虑用队列组
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的异步操作都执行完毕后,回到主线程...
}); 十三、Core Foundation
Foundation : OC
Core Foundation : C
Foundation和Core Foundation可以相互转化 NSString *str = @"123";
CFStringRef str2 = (__bridge CFStringRef)str;
NSString *str3 = (__bridge NSString *)(str2); CFArrayRef --- NSArray
CFDictionaryRef --- NSDirectory
CFNumberRef --- NSNumber 凡是函数名中带有create\copy\retain\new等字眼,都应该再不需要的时候进行release
GCD的数据类型在ARC环境下不需要release
CF(Core Foundation)的数据类型在ARC环境下还需要release Core Foundation中手动创建的数据类型,需要手动释放
CFArrayRef array = CFArrayCreate(NULL, NULL, 10, NULL);
CFRelease(array); CGPathRef path = CGPathCreateMutable();
CGPathRelease(path); 注意千万分清:主线程和主队列概念 */ @implementation IBController3 - (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
} - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"-------------------------------------"); // [self test1];
// [self test2];
// [self test3];
// [self test4];
// [self test5];
// [self test6];
[self test7];
// [self test8];
// [self test9];
NSLog(@"++++++++++++++++++++++++++++++++++++"); } /**
同步主队列
在主线程中执行
理解:主队列在同步任务的条件下,必须主线程空闲的时候,才可以添加任务到队列中
*/
- (void)test9 {
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
});
} /**
* sync(同步) --串行队列
* 会不会创建线程:不会
* 线程的执行方法:串行(一个任务执行完毕后,再执行下一个任务)
* 在主线程中执行串行队列,完成后回到主线程在执行主队列
*/
- (void)test8 {
dispatch_queue_t queue = dispatch_queue_create("bowen", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
});
} /**
* sync(同步) --并发队列
* 会不会创建线程:不会,在主线程中运行
* 任务的执行方式:串行(一个任务执行完毕后,再执行下一个任务)
* 并发队列失去并发功能
* 在主线程中执行并发队列,完成后回到主线程执行主队列
*/
- (void)test7 {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_sync(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
}); } /**
* async(异步) --主队列(很常用)(特殊)
* 会不会创建线程:不会
* 任务的执行方式:串行
* 一般用在线程之间的通讯
* 理解:异步主队列,先把任务添加到主队列中,等主线程空闲执行任务
*/
- (void)test6 {
dispatch_queue_t queue = dispatch_get_main_queue(); dispatch_async(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
});
} /**
* async(异步) --串行队列(有时用)
* 会不会创建线程:会,创建一条
* 线程的执行方法:串行(一个任务执行完毕后,再执行下一个任务)
*/
- (void)test5 {
dispatch_queue_t queue = dispatch_queue_create("bowen", DISPATCH_QUEUE_SERIAL); dispatch_async(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
}); } /**
* async(异步) --并发队列(最常用)
* 会不会创建线程:会,并且创建多条线程
* 任务的执行方式:并发执行
*/
- (void)test4 { dispatch_queue_t queue = dispatch_queue_create("bowen", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{
NSLog(@"----1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----2----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----3----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----4----%@",[NSThread currentThread]);
}); } /**
组内并行,组间串行
*/
- (void)test1 { dispatch_group_t group1 = dispatch_group_create();
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 1---%@",[NSThread currentThread]);
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 2---%@",[NSThread currentThread]); });
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 3---%@",[NSThread currentThread]); });
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 4---%@",[NSThread currentThread]); }); dispatch_group_wait(group1,DISPATCH_TIME_FOREVER); dispatch_group_t group2 = dispatch_group_create();
dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 1---%@",[NSThread currentThread]);
});
dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 2---%@",[NSThread currentThread]);
});
dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 3---%@",[NSThread currentThread]);
});
dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 4---%@",[NSThread currentThread]);
});
} - (void)test2 {
NSOperationQueue *oq = [[NSOperationQueue alloc] init];
oq.maxConcurrentOperationCount = ;
[oq addOperationWithBlock:^{
NSLog(@"1--%@",[NSThread currentThread]);
}];
[oq addOperationWithBlock:^{
NSLog(@"2--%@",[NSThread currentThread]);
}];
[oq addOperationWithBlock:^{
NSLog(@"3--%@",[NSThread currentThread]);
}];
[oq addOperationWithBlock:^{
NSLog(@"4--%@",[NSThread currentThread]);
}];
} /**
组内串行,组间并行
*/
- (void)test3 { dispatch_group_t group1 = dispatch_group_create();
dispatch_queue_t queue1 = dispatch_queue_create("leador", DISPATCH_QUEUE_SERIAL);
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 1---%@",[NSThread currentThread]);
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 2---%@",[NSThread currentThread]);
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 3---%@",[NSThread currentThread]);
});
dispatch_group_async(group1, queue1, ^{
NSLog(@"group1 --- 4---%@",[NSThread currentThread]);
}); dispatch_group_t group2 = dispatch_group_create();
dispatch_queue_t queue2 = dispatch_queue_create("leador1", DISPATCH_QUEUE_SERIAL); dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 1---%@",[NSThread currentThread]);
});
dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 2---%@",[NSThread currentThread]);
});
dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 3---%@",[NSThread currentThread]);
});
dispatch_group_async(group2, queue2, ^{
NSLog(@"group2 --- 4---%@",[NSThread currentThread]);
});
} @end
二、GCD线程之间通信
//
// ViewController.m
// IOS_0117_GCD通信
//
// Created by ma c on 16/1/17.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import "ViewController.h" @interface ViewController () @property (nonatomic, strong) UIButton *btn; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
[self.btn setFrame:CGRectMake(, , , )];
[self.btn setBackgroundColor:[UIColor purpleColor]];
[self.view addSubview:self.btn];
} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_async(queue, ^{ NSLog(@"download-----%@",[NSThread currentThread]);
//子线程下载图片
NSURL *url = [NSURL URLWithString:@"http://www.qiyue.com/uploadfile/2016/0103/20160103105808532.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data]; //回到主线程
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{ NSLog(@"刷新---------%@---%@",[NSThread currentThread],image);
[self.btn setBackgroundImage:image forState:UIControlStateNormal]; });
});
} @end
三、延迟执行
//
// ViewController.m
// IOS_0117_GCD线程通信
//
// Created by ma c on 16/1/17.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// [self delay1];
// [self delay2]; } - (void)delay3
{
NSLog(@"-----touchesBegan1------");
//3s后回到主线程执行block代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)( * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"-----task------%@",[NSThread currentThread]);
}); //3s后自动开启新线程执行block代码
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, );
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)( * NSEC_PER_SEC)), queue, ^{
NSLog(@"-----task------%@",[NSThread currentThread]);
}); NSLog(@"-----touchesBegan2------");
} - (void)delay2
{
NSLog(@"-----touchesBegan1------"); //定制好延迟任务后,不会卡主当前线程
[self performSelector:@selector(run) withObject:@"http://" afterDelay:]; NSLog(@"-----touchesBegan2------");
} - (void)run:(NSString *)url
{
NSLog(@"run------%@---%@",[NSThread currentThread], url);
} - (void)delay1
{
NSLog(@"------begin------"); //延迟线程不要用sleep,坏处:卡主线程
[NSThread sleepForTimeInterval:];
NSLog(@"下载图片");
}
@end
四、GCD一次性代码
//
// ViewController.m
// IOS_0117_GCD一次性代码
//
// Created by ma c on 16/1/17.
// Copyright (c) 2016年 博文科技. All rights reserved.
// #import "ViewController.h" @interface ViewController () @property (nonatomic, assign) BOOL hasExecuted; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
} - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// [self fun1];
[self fun2];
} - (void)fun2
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ NSLog(@"下载图片");
});
}
- (void)fun1
{
if (self.hasExecuted) return; NSLog(@"下载图片");
self.hasExecuted = YES;
} @end
五、队列组
//
// HMViewController.m
// 03-队列组(了解)
//
// Created by apple on 14-9-16.
// Copyright (c) 2014年 heima. All rights reserved.
// #import "HMViewController.h" // 1.分别下载2张图片:大图片、LOGO
// 2.合并2张图片
// 3.显示到一个imageView身上 @interface HMViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (nonatomic, strong) UIImage *image1;
@property (nonatomic, strong) UIImage *image2;
@end @implementation HMViewController - (void)viewDidLoad
{
[super viewDidLoad]; } // 2D绘图 Quartz2D
// 合并图片 -- 水印 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 1.队列组
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ); // 2.下载图片1
__block UIImage *image1 = nil;
dispatch_group_async(group, queue, ^{
NSURL *url1 = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee460de6182ff5e0fe99257e80.jpg"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
image1 = [UIImage imageWithData:data1];
}); // 3.下载图片2
__block UIImage *image2 = nil;
dispatch_group_async(group, queue, ^{
NSURL *url2 = [NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
image2 = [UIImage imageWithData:data2];
}); // 4.合并图片 (保证执行完组里面的所有任务之后,再执行notify函数里面的block)
dispatch_group_notify(group, queue, ^{
// 开启一个位图上下文
UIGraphicsBeginImageContextWithOptions(image1.size, NO, 0.0); // 绘制第1张图片
CGFloat image1W = image1.size.width;
CGFloat image1H = image1.size.height;
[image1 drawInRect:CGRectMake(, , image1W, image1H)]; // 绘制第2张图片
CGFloat image2W = image2.size.width * 0.5;
CGFloat image2H = image2.size.height * 0.5;
CGFloat image2Y = image1H - image2H;
[image2 drawInRect:CGRectMake(, image2Y, image2W, image2H)]; // 得到上下文中的图片
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文
UIGraphicsEndImageContext(); // 5.回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = fullImage;
});
});
} - (void)test2
{
// 异步下载
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
// 1.下载第1张
NSURL *url1 = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee460de6182ff5e0fe99257e80.jpg"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
self.image1 = [UIImage imageWithData:data1]; [self bindImages];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
// 2.下载第2张
NSURL *url2 = [NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
self.image2 = [UIImage imageWithData:data2]; [self bindImages];
});
} - (void)bindImages
{
if (self.image1 == nil || self.image2 == nil) return; // 3.合并图片
// 开启一个位图上下文
UIGraphicsBeginImageContextWithOptions(self.image1.size, NO, 0.0); // 绘制第1张图片
CGFloat image1W = self.image1.size.width;
CGFloat image1H = self.image1.size.height;
[self.image1 drawInRect:CGRectMake(, , image1W, image1H)]; // 绘制第2张图片
CGFloat image2W = self.image2.size.width * 0.5;
CGFloat image2H = self.image2.size.height * 0.5;
CGFloat image2Y = image1H - image2H;
[self.image2 drawInRect:CGRectMake(, image2Y, image2W, image2H)]; // 得到上下文中的图片
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文
UIGraphicsEndImageContext(); // 4.回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = fullImage;
});
} - (void)test1
{
// 异步下载
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ), ^{
// 1.下载第1张
NSURL *url1 = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee460de6182ff5e0fe99257e80.jpg"];
NSData *data1 = [NSData dataWithContentsOfURL:url1];
UIImage *image1 = [UIImage imageWithData:data1]; // 2.下载第2张
NSURL *url2 = [NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"];
NSData *data2 = [NSData dataWithContentsOfURL:url2];
UIImage *image2 = [UIImage imageWithData:data2]; // 3.合并图片
// 开启一个位图上下文
UIGraphicsBeginImageContextWithOptions(image1.size, NO, 0.0); // 绘制第1张图片
CGFloat image1W = image1.size.width;
CGFloat image1H = image1.size.height;
[image1 drawInRect:CGRectMake(, , image1W, image1H)]; // 绘制第2张图片
CGFloat image2W = image2.size.width * 0.5;
CGFloat image2H = image2.size.height * 0.5;
CGFloat image2Y = image1H - image2H;
[image2 drawInRect:CGRectMake(, image2Y, image2W, image2H)]; // 得到上下文中的图片
UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext(); // 结束上下文
UIGraphicsEndImageContext(); // 4.回到主线程显示图片
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = fullImage;
});
});
} @end
IOS-线程(GCD)的更多相关文章
- iOS多线程 GCD
iOS多线程 GCD Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法. dispatch queue分成以下三种: 1)运行在主线程的Main que ...
- iOS开发-GCD和后台处理
一些生命周期函数的调用时间 打开应用时,调用 applicationWillEnterForeground: applicationDidBecomeActive: 按Home键,调用 applica ...
- iOS's GCD Note
[iOS's GCD Note] 1.默认有四种全局concureent queue,如下: 通过以下函数来引用: 2.官方文档上并发队列有3种,实际上main就是serial. 1)serial,用 ...
- iOS 线程操作库 PromiseKit
iOS 线程操作库 PromiseKit 官网:http://promisekit.org/ github:https://github.com/mxcl/PromiseKit/tree/master ...
- IOS 线程处理 子线程
IOS 线程处理 子线程的启动与结束 技术交流新QQ群:414971585 IOS中,如果要在主线程中启动一个子线程,可以又两种方法: [NSThread detachNewThreadSelec ...
- iOS线程之——NSCondition
多线程在各种编程语言中都是难点,很多语言中实现起来很麻烦,objective-c虽然源于c,但其多线程编程却相当简单,可以与java相媲美.这篇文章主要从线程创建与启动.线程的同步与锁.线程的交互.线 ...
- ios线程和GCD
1.什么是进程? 进程是指在系统中正在运行的一个应用程序.比如同时打开QQ.Xcode,系统就会分别启动2个进程.截图 2.什么是线程? 1).一个进程要想执行任务,必须得有线程(每一个进程至少要有一 ...
- ios线程和GCD和队列同步异步的关系
1.什么是进程? 进程是指在系统中正在运行的一个应用程序.比如同时打开QQ.Xcode,系统就会分别启动2个进程.截图 2.什么是线程? 1).一个进程要想执行任务,必须得有线程(每一个进程至少要有一 ...
- iOS 开发线程 gcd
基础知识: 下午9:09 一.基础概念 1.什么是GCD 全称是Grand Central Dispath 纯C语言编写,提供非常多且强大的函数,是目前推荐的多线程开发方法,NSOperation ...
- iOS多线程---GCD中线程的通信
在子线程的任务完成后,有时候需要从子线程回到主线程,刷新UI. 从子线程中回到主线程,以前已经写过一种方法: [self.imageView performSelectorOnMainThread:@ ...
随机推荐
- E.F.Codd IBM Oracle
http://blog.sciencenet.cn/home.php?mod=space&uid=287179&do=blog&id=883429 <传奇>: “宁 ...
- Python爬虫scrapy-redis分布式实例(一)
目标任务:将之前新浪网的Scrapy爬虫项目,修改为基于RedisSpider类的scrapy-redis分布式爬虫项目,将数据存入redis数据库. 一.item文件,和之前项目一样不需要改变 # ...
- Gunicorn独角兽
1. 关于Gunicorn Gunicorn是一个开源的Python WSGI HTTP服务器,移植于Ruby的Unicorn项目的采用pre-fork模式的服务器.Gunicorn服务器可与各种We ...
- Python开发【Django】:分页、Cookie和Session
分页 1.简单分页 涉及xss攻击,需要用到mark_safe方法,使用此方法字符串传输到后端后,已html形式显示,而非字符串 HTML文件: <!DOCTYPE html> <h ...
- qt——类大全
qt类总结地址 http://www.kuqin.com/qtdocument/ QWidget.QDialog及QMainWindow的区别 QWidget类是所有用户界面对象的基类. 窗口部件是用 ...
- 【Python】自动化测试框架-共通方法汇总
1.滚动滚动条(有的时候页面元素element取得对但是并没有回显正确的数据,可能是因为页面第一次加载很慢,所以页面可能做了滚动到哪里就加载到哪里的效果,此刻我们就需要用到滚动条自动滚动这段代码让页面 ...
- java-mybaits-009-mybatis-spring-使用,SqlSessionFactoryBean、事务
一.版本限制 参看地址:http://www.mybatis.org/spring/ 二.使用入门 2.1.pom <dependency> <groupId>org.myba ...
- Atom飞行手册翻译
https://www.w3cschool.cn/atomflightmanualzhcn/
- PAT 1065 A+B and C[大数运算][溢出]
1065 A+B and C (64bit)(20 分) Given three integers A, B and C in [−263,263], you are supposed t ...
- JavaScript修改CSS属性的实例代码
用原生的javascript修改CSS属性的方法. 用JavaScript修改CSS属性 只有写原生的javascript了. 1.用JS修改标签的 class 属性值: class 属性是在标签 ...