GCD
1.什么是GCD?
-(void)testGlobalQueue
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"1%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3%@",[NSThread currentThread]);
});
}
//2.用dispatch_async异步函数往串行队列添加任务
-(void)testAsyncQueue
{
//1.创建串行队列
dispatch_queue_t queue = dispatch_queue_create("mosuyanxue", NULL);
//2.添加任务到串行队列中
dispatch_async(queue, ^{
NSLog(@"1%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3%@",[NSThread currentThread]);
});
}
//用同步函数往串行队列添加任务
-(void)testSyncQueue
{
dispatch_queue_t queue = dispatch_queue_create("mosuyanxue", NULL);
dispatch_sync(queue, ^{
NSLog(@"1%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3%@",[NSThread currentThread]);
});
}
//4.用dispatch_sync同步函数往并发队列中添加任务
<span style="background-color: rgb(255, 255, 255);">-(void)testSyncQueue2
{
dispatch_queue_t queue = dispatch_queue_create("mosuyanxue", NULL);
dispatch_sync(queue, ^{
NSLog(@"1%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3%@",[NSThread currentThread]);
});
}</span>
//5.线程异步下载图片 主线程刷新UI
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
__block UIImage * image;
UIImageView * imgView = [[UIImageView alloc]initWithFrame:CGRectMake(10, 100, 100, 100)];
[self.view addSubview:imgView];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSURL * url = [NSURL URLWithString:@"http://pic80.nipic.com/file/20151013/12964311_203654101785_2.jpg"];
NSData * data = [NSData dataWithContentsOfURL:url];
image = [UIImage imageWithData:data];
NSLog(@"%@",data);
dispatch_async(dispatch_get_main_queue(), ^{
imgView.image = image;
});
});
}
延迟执行
[NSThread sleepForTimeInterval:3];//这个尽量不要使用,会卡死当前线程。
NSLog(@"%@",@"task");
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 sleep 3s");
});
一次性代码
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
<#code to be executed once#>
});
可以用作单例的实现方法
队列组
-(void)testQueueGroup
{
//组
dispatch_group_t group = dispatch_group_create();
//队列
dispatch_queue_t queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"1%@",[NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
NSLog(@"2%@",[NSThread currentThread]);
});
dispatch_group_notify(group, queue, ^{
NSLog(@"%@",@"完成");
});
}
2.NSThread
NSThread 有两种直接创建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一个是实例方法,第二个是类方法
- 1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
- 2、NSThread* myThread = [[NSThread alloc] initWithTarget:self
- selector:@selector(doSomething:)
- object:nil];
- [myThread start];
参数的意义:
selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil
第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息
threadPriority
@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main
+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
@property double threadPriority NS_AVAILABLE(10_6, 4_0); // To be deprecated; use qualityOfService below
下载图片例子
- @implementation ViewController
- -(void)downloadImage:(NSString *) url{
- NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
- UIImage *image = [[UIImage alloc]initWithData:data];
- if(image == nil){
- }else{
- [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
- }
- }
- -(void)updateUI:(UIImage*) image{
- self.imageView.image = image;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
- NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
- [thread start];
- }
- - (void)didReceiveMemoryWarning
- {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- @end
线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:用:performSelector:onThread:withObject:waitUntilDone:
线程同步
- - (void)run{
- while (TRUE) {
- // 上锁
- // [ticketsCondition lock];
- [theLock lock];
- if(tickets >= 0){
- [NSThread sleepForTimeInterval:0.09];
- count = 100 - tickets;
- NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
- tickets--;
- }else{
- break;
- }
- [theLock unlock];
- // [ticketsCondition unlock];
- }
- }
上面例子我使用了两种锁,一种NSCondition ,一种是:NSLock。 NSCondition我已经注释了
线程的顺序执行
他们都可以通过
[ticketsCondition signal]; 发送信号的方式,在一个线程唤醒另外一个线程的等待。
比如:
- tickets = 100;
- count = 0;
- theLock = [[NSLock alloc] init];
- // 锁对象
- ticketsCondition = [[NSCondition alloc] init];
- ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
- [ticketsThreadone setName:@"Thread-1"];
- [ticketsThreadone start];
- ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
- [ticketsThreadtwo setName:@"Thread-2"];
- [ticketsThreadtwo start];
- NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];
- [ticketsThreadthree setName:@"Thread-3"];
- [ticketsThreadthree start];
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- // Override point for customization after application launch.
- self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
- self.window.rootViewController = self.viewController;
- [self.window makeKeyAndVisible];
- return YES;
- }
- -(void)run3{
- while (YES) {
- [ticketsCondition lock];
- [NSThread sleepForTimeInterval:3];
- [ticketsCondition signal];
- [ticketsCondition unlock];
- }
- }
- - (void)run{
- while (TRUE) {
- // 上锁
- [ticketsCondition lock];
- [ticketsCondition wait];
- [theLock lock];
- if(tickets >= 0){
- [NSThread sleepForTimeInterval:0.09];
- count = 100 - tickets;
- NSLog(@"当前票数是:%d,售出:%d,线程名:%@",tickets,count,[[NSThread currentThread] name]);
- tickets--;
- }else{
- break;
- }
- [theLock unlock];
- [ticketsCondition unlock];
- }
- }
其他同步
我们可以使用指令 @synchronized 来简化 NSLock的使用,这样我们就不必显示编写创建NSLock,加锁并解锁相关代码。
- (void)doSomeThing:(id)anObj
{
@synchronized(anObj)
{
// Everything between the braces is protected by the @synchronized directive.
}
}
将需要执行的操作封装到NSOperation对象
NSOperation对象放入NSOperationQueue
系统自动queue中取operation
将取出的操作放入新线程执行。
NSOperation是抽象类 不具备封装操作能力,需要使用子类
使用NSOperation子类的方式有三种。
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation实现内部相应的方法
-(void)testNSInvocationOperation
{
//1,创建操作对象 封装要执行的任务
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoad) object:nil];
//2.执行操作
[operation start];
//总结:默认情况下如果操作没有放队列中 那么默认是主线程
}
-(void)downLoad
{
NSLog(@"%@",@"逗我呢");
}
//BlockOperation
-(void)testBlockOperation
{
NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"2%@",[NSThread currentThread]);
}];
[operation addExecutionBlock:^{
NSLog(@"3%@",[NSThread currentThread]);
}];
[operation start];
//是否开启了新线程 取决于任务的个数。任务=1 主线程 任务>1开启新线程
}
/如果想异步执行任务 则需要queue队列的协助。
-(void)testOperationQueue
{
//1.封装操作
NSInvocationOperation * operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil];
NSInvocationOperation * operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
NSInvocationOperation * operation3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
//2.创建队列
NSOperationQueue * queue = [[NSOperationQueue alloc]init];
//3.将操作添加到队列中
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
-(void)download
{
NSLog(@"%@",@"download");
}
-(void)run
{
NSLog(@"%@",@"runing");
}
operation最大并发数 MaxConcurrentOperationCount = 5以内 2-3为好。
//取消队列的所有操作
[queue cancelAllOperations];
//暂停
[queue setSuspended:YES];
//operation的优先级取值
//NSOpertaion之间可以设置操作依赖。
//如让a执行完之后 才能执行操作B。可以这么写:
[operation1 addDependency:operation2];
可以在不同的operationQueue之间设置依赖关系,但是不能相互依赖。
自定义Operation
创建类继承自NSOperation
然后在.h中定义需要的属性,代理和代理方法。在.m文件中main函数写自己需要的操作。
代码如下。
@implementation CustomOperation
//在main方法中实现操作
-(void)main
{
NSURL * url = [NSURL URLWithString:self.url];
NSData * data = [NSData dataWithContentsOfURL:url];
UIImage * image = [UIImage imageWithData:data];
if (self.delegate && [self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {
[self.delegate downloadOperation:self didFinishDownload:image];
}
}
@end
#import <Foundation/Foundation.h>
@class CustomOperation;
#import <UIKit/UIKit.h>
@protocol CustomOperationDelegate<NSObject>
@optional
-(void)downloadOperation:(CustomOperation *)operation didFinishDownload:(UIImage *)image;
@end
@interface CustomOperation : NSOperation
@property (nonatomic,strong) NSIndexPath *indexpath;
@property (nonatomic,copy) NSString * url;
@property (nonatomic,assign) id<CustomOperationDelegate> delegate;
@end
检测网络状态
-(void)testNetStatus
{
//根据用户的网络状态进行处理
/*
wifi /3G自动下载高清图片
低速网络 下载缩略图
没有网络 显示离线缓存数据
苹果官方提供了一个Reachability 可检测网络状态。
*/
//wifi
Reachability * wifi = [Reachability reachabilityForLocalWiFi];
//手机自带网络功能
Reachability * conn= [Reachability reachabilityForInternetConnection];
if ([wifi currentReachabilityStatus ]!= NotReachable) {
NSLog(@"%@",@"wifi");
}else if ([conn currentReachabilityStatus] != NotReachable){
NSLog(@"%@",@"有手机网络");
}else{
NSLog(@"%@",@"没有网络");
}
}
Reachability还可以实时监控网络状态。添加通知,如果网络有问题就通知。