Effective Objective-C 2.0

📚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);
        }
    });

}
上一篇 下一篇

猜你喜欢

热点阅读