📚Effective OC - Tip 43 , 44 , 45
2017-01-12 本文已影响47人
小万叔叔
掌握 GCD 和操作队列的使用时机
//自定义NSOperation
@interface CustomNSOperation()
//需要设置, 不然不能释放Operation,cancel 里面调用 setFinished , 发出KVO 才会释放
@property (assign, nonatomic, getter = isExecuting) BOOL executing;
@property (assign, nonatomic, getter = isFinished) BOOL finished;
@end
@implementation CustomNSOperation {
}
@synthesize executing = _executing;
@synthesize finished = _finished;
- (void)dealloc{
NSLog(@"dealloc CustomNSOperation");
}
- (void)cancel {
NSLog(@"cancel CustomNSOperation");
[super cancel];
self.finished = YES;
}
- (void)setExecuting:(BOOL)executing {
[self willChangeValueForKey:@"isExecuting"];
_executing = executing;
[self didChangeValueForKey:@"isExecuting"];
}
- (void)setFinished:(BOOL)finished {
[self willChangeValueForKey:@"isFinished"];
_finished = finished;
[self didChangeValueForKey:@"isFinished"];
}
- (void)main {
NSLog(@"do CustomNSOperation");
}
@end
/**
* NSOperationQueue 和 NSOperation 的优点
* 1. 可以cancel
* 2. 可以添加dependencies
* 3. 可以 KVO
* 4. 可以指定操作的优先级
*/
//获取当前线程的方法用[NSThread currentThread] , 而不是 dispatch_get_current_queue ,
// NSBlockOperation 直接start ,会并发执行所有block,也会再当前的队列上执行
// 而被添加到 operationQueue 则按照 Queue 的模式来并发执行
- (void)testNSOperation {
//NSBlockOperation
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
sleep(3);
NSLog(@"blockOperation 1 %@", [NSThread currentThread]);
}];
[operation addExecutionBlock:^{
sleep(1);
NSLog(@"blockOperation 2 %@", [NSThread currentThread]);
}];
[operation addExecutionBlock:^{
sleep(2);
NSLog(@"blockOperation 3 %@", [NSThread currentThread]);
}];
[operation setCompletionBlock:^{
NSLog(@"blockOperation 4 %@", [NSThread currentThread]);
}];
[operation setCompletionBlock:^{
NSLog(@"completed blockOperation %@", [NSThread currentThread]);
}];
// [operation start];
//NSInvocationOperation
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(invocationMessage)
object:nil];
//
[invocationOperation setQualityOfService:NSQualityOfServiceUserInteractive];
[invocationOperation setQualityOfService:NSQualityOfServiceUserInitiated];
[invocationOperation setQualityOfService:NSQualityOfServiceUtility];
[invocationOperation setQualityOfService:NSQualityOfServiceBackground];
[invocationOperation setQualityOfService:NSQualityOfServiceDefault];
[invocationOperation setQualityOfService:NSQualityOfServiceBackground];
[_operationQueue addOperation:invocationOperation];
//CustomNSOperation
CustomNSOperation *customNSOperation = [CustomNSOperation new];
[_operationQueue addOperation:customNSOperation];
NSLog(@"------ end %@", [NSThread currentThread]);
_operationQueue.maxConcurrentOperationCount = 2;
[_operationQueue addOperation:operation];
// [_operationQueue waitUntilAllOperationsAreFinished]; //会阻塞知道任务完成
[_operationQueue cancelAllOperations];
}
- (void)invocationMessage {
NSLog(@"enter invocationOperation");
}
通过 Dispatch Group 机制,根据系统资源状况来执行任务
/*
* 1. dispatch_notify 方案
* dispatch_group_async(group, dispatch_get_main_queue()
* dispatch_notify(group, dispatch_get_main_queue(),
* 2. dispatch_group_wait 阻塞
* dispatch_group_enter(group);
* dispatch_group_leave(group);
* dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
* dispatch_group_async 相当于 dispatch_group_enter 和 dispatch_group_leave
* 3. dispatch_apply 多次
*
*/
- (void)caseOne {
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_group_async(group, dispatch_get_main_queue(), ^{
dispatch_group_leave(group);
NSLog(@"Task 1");
});
dispatch_group_async(group, dispatch_get_main_queue(), ^{
NSLog(@"Task 1");
});
dispatch_group_async(group, dispatch_get_main_queue(), ^{
NSLog(@"Task 1");
});
dispatch_group_async(group, dispatch_get_main_queue(), ^{
NSLog(@"Task 1");
});
dispatch_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"Task finished");
});
NSLog(@"我直接过来了");
}
- (void)caseTwo {
dispatch_queue_t queue = dispatch_queue_create("hello", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(queue, ^{
dispatch_group_leave(group);
NSLog(@"Task 1");
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
dispatch_group_leave(group);
NSLog(@"Task 2");
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
sleep(10);
dispatch_group_leave(group);
NSLog(@"Task 3");
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"过来了");
}
- (void)caseThree {
dispatch_queue_t queue = dispatch_queue_create("hello", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, queue, ^(size_t i) {
NSLog(@"== output is %@", @(i));
});
}
使用 dispatch_once 来执行只需运行一次的线程安全代码
/*
* dispatch_once_t
* 整个情况下只运行一次的情况,特别适合单例,而且单例对象指针已经全局分配
*/
- (void)caseOnce {
static dispatch_once_t once;
static GCD* singleInstance = nil;
dispatch_once(&once, ^{
singleInstance = [GCD new];
});
}
不要使用 dispatch_get_current_queue
/* 1. dispatch_get_current_queue 已被废弃,因为
* Global_Queue(并发)
* |
* ------------
* | |
* QueueC QueueD
* -------
* | |
* QueueA QueueB
* 有这种关系存储,所以很难使用 dispatch_get_current_queue 准确的获取到当前 block_t 的 queue
*
* 2. 队列特定值,这个值只与队列绑定,如果属于上面的继承树,则会一直向上追溯,直到找到数据为止。
* dispatch_queue_set_specific(queueA, &kQueueSpecific, queueSpecificValue, CFRelease);
dispatch_get_specific(&kQueueSpecific) //获取当前队列的特定值
//以下是一种避免死锁的操作
*/
- (void)caseCurrentThread {
NSLog(@"%@", dispatch_get_current_queue());
dispatch_queue_t queueA = dispatch_queue_create("queueA", NULL);
static int kQueueSpecific;
CFStringRef queueSpecificValue = CFSTR("queueA");
dispatch_queue_set_specific(queueA, &kQueueSpecific, queueSpecificValue, CFRelease);
dispatch_sync(queueA, ^{
dispatch_block_t block = ^{
NSLog(@"No dead lock");
};
CFStringRef value = dispatch_get_specific(&kQueueSpecific);
if (value) {
block();
} else {
dispatch_sync(queueA, block);
}
});
}