NSTimer Category + Blocks implementation to replace selector

后端 未结 3 664
清歌不尽
清歌不尽 2021-01-06 20:16

I am quite new to blocks and objective-c, and i am trying to write my first category using both. My idea is to create a category on NSTimer that will receive a block as a pa

3条回答
  •  抹茶落季
    2021-01-06 20:52

    Your major flaw besides the wrong target is your use of a static variable. You won't be able to support beyond a single timer.

    Using block as argument to the invoked method.

    @interface NSTimer (AdditionsPrivate) // Private stuff
    - (void)theBlock:(VoidBlock)voidBlock;
    @end
    
    
    @implementation NSTimer (NSTimer_Additions)
    
    + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
        NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(theBlock:)]];
        NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:theSeconds
                                                       invocation:invocation
                                                          repeats:repeats];
        [invocation setTarget:timer];
        [invocation setSelector:@selector(theBlock:)];
        
        Block_copy(actions);
        [invocation setArgument:&actions atIndex:2];
        Block_release(actions);
    
        return timer;
    }
    
    
    - (void)theBlock:(VoidBlock)voidBlock {
        voidBlock();
    }
    
    @end
    

    The problem with using associative references was the leak as there was no good point to release the block.


    Earlier Approach using associative references

    You can use associative references to attach the block to that particular instance of NSTimer.

    @implementation NSTimer (NSTimer_Additions)
    
    + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
        NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(theBlock)]];
        NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:theSeconds
                                                       invocation:invocation
                                                          repeats:repeats];
        [invocation setTarget:timer];
        [invocation setSelector:@selector(theBlock)];
    
        objc_setAssociatedObject(timer, @"Block", actions, OBJC_ASSOCIATION_COPY);
        
        return timer;
    }
    
    
    - (void)theBlock {
        VoidBlock _voidBlock = (VoidBlock)objc_getAssociatedObject(self, @"Block");
        _voidBlock();
    }
    
    @end
    

提交回复
热议问题