iOS多线程总结
2016-05-09 16:40
423 查看
线程的注意点:
1.不要同时开太多的线程(1~3条线程即可,不要超过5条)
2.线程概念:
1>主线程:UI线程,显示、刷新UI界面,处理UI控件的事件
2>子线程:后台线程,异步线程
3.不要把耗时的操作放在主线程,要放到子线程中执行
一、NSThread
1.创建和启动线程的三种方式
1>先创建,后启动
//创建
NSThread *thread = [[NSThread alloc] initWihtTarget:self selector:@selector(download:) object:nil];
//启动
[thread start];
2>创建完自动启动
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://a.jpg"];
3>隐式创建(自动启动)
[self performSelectorInBackground:@selector(download:) withObject:@"http://c.gif"];
2.常见方法
1>获得当前线程
+ (NSThread *)currentThread;
2>获得主线程
+ (NSThread *)mainThread;
3>睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4>设置线程的名字
- (void)setName:(NSString *)name;
- (NSString *)name;
3.线程同步
1>实质:为了防止多个线程抢夺同一个资源造成的数据安全问题
2>实现:给代码加一个互斥锁(同步锁)
@synchronized (self) {
//被锁住的代码
}
二、GCD
// dispatch_sync : 同步,不具备开启线程的能力
// dispatch_async : 异步,具备开启线程的能力
// 并发队列:多个任务可以同时执行
// 串行队列:一个任务执行完后,再执行下一个任务
1.队列和任务
1>任务:需要执行什么操作
*用block来封装任务
2>队列:存放任务
(1)全局的并发队列:可以让任务并发执行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, ^{//将任务添加全局队列中去异步执行
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
(2)自己创建的串行队列:让任务一个接一个地执行
dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue",NULL);
dispatch_async(queue, ^{// 2.将任务添加到串行队列中异步执行
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
(3)主队列
// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.添加任务到主队列中异步执行
dispatch_async(queue, ^{
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
2.执行任务的函数
1>dispatch_sync :同步,不具备开启线程的能力
*注意:dispatch_sync不能使用主队列(会被卡死){
// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.添加任务到主队列中异步执行
dispatch_sync(queue, ^{
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
}
2>dispatch_async :异步,具备开启线程的能力
3.常见的组合
1>dispatch_async +全局并发队列
2>dispatch_async +自己创建的串行队列
4.线程间的通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSLog(@"donwload---%@", [NSThread currentThread]);
// 1.子线程下载图片
NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 2.回到主线程设置图片
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"setting---%@ %@", [NSThread currentThread], image);
[self.button setImage:image forState:UIControlStateNormal];
});
});
5.GCD的所有API都在libdispatch.dylib,Xcode会自动导入这个库
*主头文件: #import <dispatch/dispatch.h>
6.延时执行
1>3秒后自动回到当前线程调用self的download:方法。并且传递参数:@"http://555.jpg"
// 一旦定制好延迟任务后,不会卡住当前线程
[self performSelector:@selector(download:) withObject:@"http://555.jpg"
afterDelay:3];
2>// 3秒后自动开启新线程执行block中的代码
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
NSLog(@"------task------%@", [NSThread currentThread]);
});
7.一次性代码
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{//这里面的代码永远只会执行一次
NSLog(@"----once");
});
三、NSOperation
作用:配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤:
先将需要执行的操作封装到一个NSOperation对象中,然后将NSOperation对象添加到NSOperationQueue中,系统会自动将NSOperationQueue中的NSOperation取出来,并把封装的操作放到一条新线程中执行。
NSOperation是一个抽象类,并不具备封装操作的能力,必须使用它的子类。
使用NSOperation子类的方式有3种:
(1).NSInvocationOperation
{// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 创建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
// operation直接调用start,是同步执行(在当前线程执行操作)
// [operation start];
//
添加操作到队列中,会自动异步执行
[queue addOperation:operation];
}
- (void)download
{
NSLog(@"download-----%@", [NSThread currentThread]);
}
(2).NSBlockOperation
(3).自定义子类继承NSOperation,实现内部相应的方法
1.队列的类型
1>主队列
*主队列:[NSOperationQueue mainQueue];
*添加到“主队列”中的操作,都会放到主线程中执行。
2>非主队列
*创建一个队列(非主队列)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
*添加到"非主队列"中的操作,都会放到子线程中执行
2.队列添加任务
* - (void)addOperation:(NSOperation *)op;
* - (void)addOperationWithBlock:(void (^)(void))block;
3.常见用法
1>
设置最大并发数
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
2>队列的其他操作
*取消所有的操作
- (void)cancelAllOperations;
*暂停所有操作
[queue setSuspended:YES];
*恢复所有操作
[queue setSuspended:NO];
4.操作之间的依赖
*NSOperation之间可以设置依赖来保证执行顺序
*[operationB addDependency:operationA];//操作B依赖于操作A(只有操作A执行完以后才能执行操作B)
*注意:不能相互依赖,比如A依赖B,B依赖A
*可以在不同queue的NSOperation之间创建依赖关系
5.线程之间的通讯
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1.异步下载图片(执行一些比较耗时的操作)
NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 2.回到主线程,显示图片
// [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
// dispatch_async(dispatch_get_main_queue(), ^{
//
// });
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
四、从其他线程回到主线程的方式:
1.perform....
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
2.GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
3.NSOperation
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
五、判断编译器的环境:ARC还是MRC?
#if __has_feature(objc_arc)
//当前的编译器环境是ARC
#else
//当前的编译器环境是MRC
#endif
1.不要同时开太多的线程(1~3条线程即可,不要超过5条)
2.线程概念:
1>主线程:UI线程,显示、刷新UI界面,处理UI控件的事件
2>子线程:后台线程,异步线程
3.不要把耗时的操作放在主线程,要放到子线程中执行
一、NSThread
1.创建和启动线程的三种方式
1>先创建,后启动
//创建
NSThread *thread = [[NSThread alloc] initWihtTarget:self selector:@selector(download:) object:nil];
//启动
[thread start];
2>创建完自动启动
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://a.jpg"];
3>隐式创建(自动启动)
[self performSelectorInBackground:@selector(download:) withObject:@"http://c.gif"];
2.常见方法
1>获得当前线程
+ (NSThread *)currentThread;
2>获得主线程
+ (NSThread *)mainThread;
3>睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4>设置线程的名字
- (void)setName:(NSString *)name;
- (NSString *)name;
3.线程同步
1>实质:为了防止多个线程抢夺同一个资源造成的数据安全问题
2>实现:给代码加一个互斥锁(同步锁)
@synchronized (self) {
//被锁住的代码
}
二、GCD
// dispatch_sync : 同步,不具备开启线程的能力
// dispatch_async : 异步,具备开启线程的能力
// 并发队列:多个任务可以同时执行
// 串行队列:一个任务执行完后,再执行下一个任务
1.队列和任务
1>任务:需要执行什么操作
*用block来封装任务
2>队列:存放任务
(1)全局的并发队列:可以让任务并发执行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, ^{//将任务添加全局队列中去异步执行
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
(2)自己创建的串行队列:让任务一个接一个地执行
dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue",NULL);
dispatch_async(queue, ^{// 2.将任务添加到串行队列中异步执行
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
(3)主队列
// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.添加任务到主队列中异步执行
dispatch_async(queue, ^{
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
2.执行任务的函数
1>dispatch_sync :同步,不具备开启线程的能力
*注意:dispatch_sync不能使用主队列(会被卡死){
// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)
dispatch_queue_t queue = dispatch_get_main_queue();
// 2.添加任务到主队列中异步执行
dispatch_sync(queue, ^{
NSLog(@"-----下载图片1---%@", [NSThread currentThread]);
});
}
2>dispatch_async :异步,具备开启线程的能力
3.常见的组合
1>dispatch_async +全局并发队列
2>dispatch_async +自己创建的串行队列
4.线程间的通信
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSLog(@"donwload---%@", [NSThread currentThread]);
// 1.子线程下载图片
NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 2.回到主线程设置图片
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"setting---%@ %@", [NSThread currentThread], image);
[self.button setImage:image forState:UIControlStateNormal];
});
});
5.GCD的所有API都在libdispatch.dylib,Xcode会自动导入这个库
*主头文件: #import <dispatch/dispatch.h>
6.延时执行
1>3秒后自动回到当前线程调用self的download:方法。并且传递参数:@"http://555.jpg"
// 一旦定制好延迟任务后,不会卡住当前线程
[self performSelector:@selector(download:) withObject:@"http://555.jpg"
afterDelay:3];
2>// 3秒后自动开启新线程执行block中的代码
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
NSLog(@"------task------%@", [NSThread currentThread]);
});
7.一次性代码
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{//这里面的代码永远只会执行一次
NSLog(@"----once");
});
三、NSOperation
作用:配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤:
先将需要执行的操作封装到一个NSOperation对象中,然后将NSOperation对象添加到NSOperationQueue中,系统会自动将NSOperationQueue中的NSOperation取出来,并把封装的操作放到一条新线程中执行。
NSOperation是一个抽象类,并不具备封装操作的能力,必须使用它的子类。
使用NSOperation子类的方式有3种:
(1).NSInvocationOperation
{// 创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 创建操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
// operation直接调用start,是同步执行(在当前线程执行操作)
// [operation start];
//
添加操作到队列中,会自动异步执行
[queue addOperation:operation];
}
- (void)download
{
NSLog(@"download-----%@", [NSThread currentThread]);
}
(2).NSBlockOperation
(3).自定义子类继承NSOperation,实现内部相应的方法
1.队列的类型
1>主队列
*主队列:[NSOperationQueue mainQueue];
*添加到“主队列”中的操作,都会放到主线程中执行。
2>非主队列
*创建一个队列(非主队列)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
*添加到"非主队列"中的操作,都会放到子线程中执行
2.队列添加任务
* - (void)addOperation:(NSOperation *)op;
* - (void)addOperationWithBlock:(void (^)(void))block;
3.常见用法
1>
设置最大并发数
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
2>队列的其他操作
*取消所有的操作
- (void)cancelAllOperations;
*暂停所有操作
[queue setSuspended:YES];
*恢复所有操作
[queue setSuspended:NO];
4.操作之间的依赖
*NSOperation之间可以设置依赖来保证执行顺序
*[operationB addDependency:operationA];//操作B依赖于操作A(只有操作A执行完以后才能执行操作B)
*注意:不能相互依赖,比如A依赖B,B依赖A
*可以在不同queue的NSOperation之间创建依赖关系
5.线程之间的通讯
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1.异步下载图片(执行一些比较耗时的操作)
NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 2.回到主线程,显示图片
// [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
// dispatch_async(dispatch_get_main_queue(), ^{
//
// });
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];
四、从其他线程回到主线程的方式:
1.perform....
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
2.GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
3.NSOperation
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
五、判断编译器的环境:ARC还是MRC?
#if __has_feature(objc_arc)
//当前的编译器环境是ARC
#else
//当前的编译器环境是MRC
#endif
相关文章推荐
- iOS性能优化:Instruments使用实战(转)
- iOS 对字符串压缩
- 跳转到系统设置
- iOS 计算沙盒目录下一个文件夹的总大小
- IOS 中说一个文件找不到或者说一个文件重复的时候
- 一种简便的ios图片加密方法-对图片进行base64编码
- 一步步教你学会iOS真机调试,常见证书问题的解决方案以及Xcode7之后免$99真机调试
- iOS开发中一些常用的方法
- iOS字体包导入过程
- iOS -- 定时器
- ios UTC 时间格式转换
- iOS备忘录之开发经验总结
- iOS new和alloc init的区别
- iOS编译好的FFMPEG-iOS以及kxmovie播放视频的小demo
- IOS开发 self点语法与指针语法的区别
- iOS应用程序启动时所有方法的调用顺序
- iOS推送之远程推送
- iOS极光推送 点击推送消息跳转页面
- AVAudioSession
- iOS 生成本地验证码