美文网首页
GCD应用:没什么卵用的 Cancelable Queue

GCD应用:没什么卵用的 Cancelable Queue

作者: 刺客辣条 | 来源:发表于2016-11-18 19:39 被阅读0次

    方式一:

    dispatch_cancelable_block.h:

    //
    //  dispatch_cancelable_block.h
    //  TestProj
    //
    //  Created by Wesley on 2016/11/17.
    //  Copyright © 2016年 Wesley. All rights reserved.
    //
    
    #ifndef dispatch_cancelable_block_h
    #define dispatch_cancelable_block_h
    
    typedef void(^dispatch_cancelable_block_t)(BOOL cancel);
    
    static dispatch_cancelable_block_t dispatch_after_delay(CGFloat delay, dispatch_block_t block) {
        if (block == nil)
            return nil;
        
        // First we have to create a new dispatch_cancelable_block_t and we also need to copy the
        // block given (if you want more explanations about the __block storage type, read this:
        // https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6
        __block dispatch_cancelable_block_t cancelableBlock = nil;
        __block dispatch_block_t originalBlock = [block copy];
        
        // This block will be executed in NOW() + delay
        dispatch_cancelable_block_t delayBlock = ^(BOOL cancel){
            if (cancel == NO && originalBlock)
                dispatch_async(dispatch_get_main_queue(), originalBlock);
            
            // We don't want to hold any objects in the memory
            originalBlock = nil;
            cancelableBlock = nil;
        };
        
        cancelableBlock = [delayBlock copy];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            // We are now in the future (NOW() + delay). It means the block hasn't been canceled so we can execute it
            if (cancelableBlock)
                cancelableBlock(NO);
        });
        
        return cancelableBlock;
    }
    
    static void cancel_block(dispatch_cancelable_block_t block) {
        if (block == nil)
            return;
        
        block(YES);
    }
    
    #endif /* dispatch_cancelable_block_h */
    

    Usage:

    #import "dispatch_cancelable_block.h"
    
    dispatch_cancelable_block_t cblock = dispatch_after_delay(2.0, ^(void){
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i = 0; i < 10; ++i) {
                void (^ablock)(BOOL) = ^(BOOL b) {
                    NSLog(@"BOOL = %d", b);
                };
                ablock(YES);
                sleep(1.0);
            }
        });
    });
    
    cancel_block(cblock);
    

    方式二:

    NSObject+Blocks.h

    //
    //  NSObject+Blocks.h
    //  TestProj
    //
    //  Created by Wesley on 2016/11/17.
    //  Copyright © 2016年 Wesley. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface NSObject (Blocks)
    
    + (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay;
    + (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay;
    - (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay;
    - (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay;
    
    + (void)cancelBlock:(id)block;
    
    @end
    

    NSObject+Blocks.m

    //
    //  NSObject+Blocks.m
    //  TestProj
    //
    //  Created by Wesley on 2016/11/17.
    //  Copyright © 2016年 Wesley. All rights reserved.
    //
    
    #import "NSObject+Blocks.h"
    #import <dispatch/dispatch.h>
    
    static inline dispatch_time_t dTimeDelay(NSTimeInterval time) {
        int64_t delta = (int64_t)(NSEC_PER_SEC * time);
        return dispatch_time(DISPATCH_TIME_NOW, delta);
    }
    
    @implementation NSObject (Blocks)
    
    + (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
        if (!block) return nil;
        
        __block BOOL cancelled = NO;
        
        void (^wrappingBlock)(BOOL) = ^(BOOL cancel) {
            if (cancel) {
                cancelled = YES;
                return;
            }
            if (!cancelled)block();
        };
    
        wrappingBlock = [wrappingBlock copy];
        
        dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{  wrappingBlock(NO); });
        
        return wrappingBlock;
    }
    
    + (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay {
        if (!block) return nil;
        
        __block BOOL cancelled = NO;
        
        void (^wrappingBlock)(BOOL, id) = ^(BOOL cancel, id arg) {
            if (cancel) {
                cancelled = YES;
                return;
            }
            if (!cancelled) block(arg);
        };
        
        wrappingBlock = [wrappingBlock copy];
        dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{  wrappingBlock(NO, anObject); });
        
        return wrappingBlock;
    }
    
    - (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
        if (!block) return nil;
        
        __block BOOL cancelled = NO;
        
        void (^wrappingBlock)(BOOL) = ^(BOOL cancel) {
            if (cancel) {
                cancelled = YES;
                return;
            }
            if (!cancelled) block();
        };
    
        wrappingBlock = [wrappingBlock copy];
    
        dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{  wrappingBlock(NO); });
    
        return wrappingBlock;
    }
    
    - (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay {
        if (!block) return nil;
        
        __block BOOL cancelled = NO;
        
        void (^wrappingBlock)(BOOL, id) = ^(BOOL cancel, id arg) {
            if (cancel) {
                cancelled = YES;
                return;
            }
            if (!cancelled) block(arg);
        };
        
        wrappingBlock = [wrappingBlock copy];
        
        dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{  wrappingBlock(NO, anObject); });
        
        return wrappingBlock;
    }
    
    + (void) cancelBlock:(id)block {
        if (!block) return;
        void (^aWrappingBlock)(BOOL) = (void(^)(BOOL))block;
        aWrappingBlock(YES);
    }
    
    @end
    

    Usage:

    #import "NSObject+Blocks.h"
    
    typedef void(^theBlock)(void);
    
    theBlock _theblock = [self performBlock:^(void){
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            for (int i = 0; i < 10; ++i) {
                NSLog(@"cblock %d", i);
                sleep(1.0);c
            }
        });
    } afterDelay:2.0];
    
    [ViewController cancelBlock:_theblock];
    

    相关文章

      网友评论

          本文标题:GCD应用:没什么卵用的 Cancelable Queue

          本文链接:https://www.haomeiwen.com/subject/ehdspttx.html