1.子线程中代理回调
**子线程中默认没有唤醒Runloop,所以delegate默认无法在子线程中回调**
**子线程异步请求 创建runloop 在runloop中添加代理 设置nsmachport 进行线程通讯,调用方法 执行子线程,相关代理执行,逆地理编码成功后 移除通讯 **
- (void)location{
dispatch_queue_t deleQue = dispatch_queue_create("haha", DISPATCH_QUEUE_SERIAL);
dispatch_async(deleQue, ^{
_runloop = [NSRunLoop currentRunLoop];
_port = [NSMachPort port];
[_runloop addPort:_port forMode:NSDefaultRunLoopMode];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[self startLocation];
[_runloop run];
});
}
- (void)startLocation
{
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
NSLog(@"开始定位");
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
//逆地理编码
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray<CLPlacemark> * _Nullable placemarks, NSError * _Nullable error) {
if (error || [placemarks count] == 0)
{
NSLog(@"逆地理编码错误,error = %@", error);
return;
}
NSDictionary *addressDic = [[placemarks objectAtIndex:0] addressDictionary];
[_runloop removePort:_port forMode:NSDefaultRunLoopMode];
if (_locationSuccess) {
_locationSuccess(addressDic);
}
NSLog(@"dic = %@",addressDic);
}];
[manager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
if (error.code == kCLErrorDenied) {
}
NSLog(@"定位失败");
}
2.线程依赖
1) //NSOperationQueue 线程之前添加依赖操作
-(void)dependency{
/**
假设有A、B、C三个操作,要求:
1. 3个操作都异步执行
2. 操作C依赖于操作B
3. 操作B依赖于操作A
*/
//创建一个队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//可开辟线程的最大数量
queue.maxConcurrentOperationCount = 3;
//创建三个任务
NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"A任务当前线程为:%@", [NSThread currentThread]);
}];
NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"B任务当前线程为:%@", [NSThread currentThread]);
}];
NSBlockOperation *operationC = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"C任务当前线程为:%@", [NSThread currentThread]);
}];
//设置三个任务相互依赖
// operationB 任务依赖于 operationA
[operationB addDependency:operationA];
// operationC 任务依赖于 operationB
[operationC addDependency:operationB];
//添加操作到队列中(自动异步执行任务,并发)
[queue addOperation:operationA];
[queue addOperation:operationB];
[queue addOperation:operationC];
[NSOpeationQueue mainQueue] addOperation ^{
}];
}
** 2)GCD**
当dispatch_group_async的block里面执行的是异步任务,如果还是使用上面的方法你会发现异步任务还没跑完就已经进入到了dispatch_group_notify方法里面了,这时用到dispatch_group_enter和dispatch_group_leave就可以解决这个问题:
#pragma mark - 下载基础数据
- (void)downloadBaseData
{
// 全局变量group
group = dispatch_group_create();
// 并行队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 进入组(进入组和离开组必须成对出现, 否则会造成死锁)
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
// 执行异步任务1
[self fetchBaseData];
dispatch_group_leave(group);
});
// 进入组
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
// 执行异步任务2
[self fetchInspectorBaseData];
dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
ILog(@"全部基础数据下载完毕!");
[[AppDelegate sharedDelegate] showMainView];
});
3.目标队列相关
+(void)testTargetQueue {
dispatch_queue_t targetQueue = dispatch_queue_create("test.target.queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue1 = dispatch_queue_create("test.1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("test.2", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue3 = dispatch_queue_create("test.3", DISPATCH_QUEUE_SERIAL);
dispatch_set_target_queue(queue1, targetQueue);
dispatch_set_target_queue(queue2, targetQueue);
dispatch_set_target_queue(queue3, targetQueue);
dispatch_async(queue1, ^{
NSLog(@"1 in");
[NSThread sleepForTimeInterval:3.f];
NSLog(@"1 out");
});
dispatch_async(queue2, ^{
NSLog(@"2 in");
[NSThread sleepForTimeInterval:2.f];
NSLog(@"2 out");
});
dispatch_async(queue3, ^{
NSLog(@"3 in");
[NSThread sleepForTimeInterval:1.f];
NSLog(@"3 out");
});
}
输出
1 in
1 out
2 in
2 out
3 in
3 out
4.自定义串行队列 ?
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, -1);
return dispatch_queue_create("com.lotus.LCQueueForUserInteractive", attr);;
4.线程安全 ?
1.多读单写
- (void)creatCGDReadAndWriter {
//创建一个队列
dispatch_queue_t queue = dispatch_queue_create("oneQueue", DISPATCH_QUEUE_CONCURRENT);
//多个任务同时执行读操作
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"read1:%d",i);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"read2:%d",i);
}
});
//执行写操作
/*
下面这个函数在加入队列时不会执行,会等待已经开始的异步执行全部完成后再执行,并且在执行时会阻塞其他任务
当执行完成后,其他任务重新进入异步执行
*/
dispatch_barrier_async(queue, ^{
for (int i = 0; i < 5; i ++) {
NSLog(@"writer:%d",i);
}
});
//绩效执行异步操作
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"read3:%d",i);
}
});
dispatch_async(queue, ^{
for (int i = 0; i < 5; i++) {
NSLog(@"read4:%d",i);
}
});
}
2.限制线程的最大并发数
- (void)creatGCDSinger {
//创建一个信号,其中的参数是信号的初始值
dispatch_semaphore_t singer = dispatch_semaphore_create(2);
for (int i = 0; i < 15; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//等待信号,当信号量大于0时,执行后面的代码,否则等待,第二个参数为等待的超时时长,下面设置的为一直等待
dispatch_semaphore_wait(singer, DISPATCH_TIME_FOREVER);
//doing
sleep(1);
//发送信号,信号量+1
dispatch_semaphore_signal(singer);
});
}
}
3.信号量控制网络请求顺序
- (void)creatGCDSinger {
//创建semp
dispatch_semaphore_t semp = dispatch_semaphore_create(1);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//任务1
dispatch_async(queue, ^{
//信号量-1
dispatch_semaphore_wait(semp, DISPATCH_TIME_FOREVER);
//模拟网络请求
//模拟网络请求-异步
//每次网络请求成功或失败后,都让信号量+1,表示释放当前资源,其他线程可以抢占了
[[KNetRequestManager share] getSomeData:^{
//网络请求成功,发送信号
dispatch_semaphore_signal(sema);
} errorBlock:^{
//网络请求失败,发送信号
dispatch_semaphore_signal(sema);
}];
});
//任务2
dispatch_async(queue, ^{
//信号量-1
dispatch_semaphore_wait(semp, DISPATCH_TIME_FOREVER);
//模拟网络请求
//模拟网络请求-异步
//每次网络请求成功或失败后,都让信号量+1,表示释放当前资源,其他线程可以抢占了
[[KNetRequestManager share] getSomeData:^{
//网络请求成功,发送信号
dispatch_semaphore_signal(sema);
} errorBlock:^{
//网络请求失败,发送信号
dispatch_semaphore_signal(sema);
}];
});
}
5.dispatch_once实现原理