Awhisper/VKMsgSend

throttle

JunyiXie opened this issue · 0 comments

#import "NSObject+JYThrottle.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "VKMsgSend.h"

static char XJYThrottle;
static char XJYThrottleQueue;

@implementation NSObject (JYThrottle)

- (void)xjy_performSelector:(SEL)aSelector error:(NSError *__autoreleasing *)error withThrottle:(NSTimeInterval)inteval,... {
    va_list argList;
    va_start(argList, error);
    NSArray* boxingArguments = vk_targetBoxingArguments(argList, [self class], aSelector, error);
    va_end(argList);
    
    if (!boxingArguments) {
        return ;
    }
    
    dispatch_async([self getSerialQueue], ^{
        NSMutableDictionary *blockedSelectors = [objc_getAssociatedObject(self, &XJYThrottle) mutableCopy];
        
        if (!blockedSelectors) {
            blockedSelectors = [NSMutableDictionary dictionary];
            objc_setAssociatedObject(self, &XJYThrottle, blockedSelectors, OBJC_ASSOCIATION_COPY_NONATOMIC);
        }
        
        NSString *selectorName = NSStringFromSelector(aSelector);
        if (![blockedSelectors objectForKey:selectorName]) {
            [blockedSelectors setObject:selectorName forKey:selectorName];
            objc_setAssociatedObject(self, &XJYThrottle, blockedSelectors, OBJC_ASSOCIATION_COPY_NONATOMIC);
            dispatch_async(dispatch_get_main_queue(), ^{
                vk_targetCallSelectorWithArgumentError(self, aSelector, boxingArguments, error);
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(inteval * NSEC_PER_SEC)), [self getSerialQueue], ^{
                    [self xjy_unlockSelector:selectorName];
                });
            });
        }
    });
}




#pragma mark -
- (void)xjy_unlockSelector:(NSString *)selectorName
{
    dispatch_async([self getSerialQueue], ^{
        NSMutableDictionary *blockedSelectors = [objc_getAssociatedObject(self, &XJYThrottle) mutableCopy];
        
        if ([blockedSelectors objectForKey:selectorName]) {
            [blockedSelectors removeObjectForKey:selectorName];
        }
        
        objc_setAssociatedObject(self, &XJYThrottle, blockedSelectors, OBJC_ASSOCIATION_COPY_NONATOMIC);
    });
}

- (dispatch_queue_t)getSerialQueue
{
    dispatch_queue_t serialQueur = objc_getAssociatedObject(self, &XJYThrottleQueue);
    if (!serialQueur) {
        serialQueur = dispatch_queue_create("com.satanwoo.throttle", NULL);
        objc_setAssociatedObject(self, &XJYThrottleQueue, serialQueur, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return serialQueur;
}

@end