Objective-C异步任务。如何在多次调用时只运行一次函数?

时间:2014-06-04 02:30:50

标签: ios objective-c

我有一个异步调用多次的函数。每次我需要它做的是等待几个运行循环(或只需0.1秒就可以了),以确保它不会被其他任何地方调用。如果从其他地方调用它,请跳过该函数并让最新的调用执行代码(而代码会等待一小段时间检查它是否再次被调用)。

它只需要执行一次代码块,但它需要执行最新的数据。同时发生几次重要数据更新的可能性很高。可以把它想象成一个"检查没有更重要信息的人现在应该运行这个代码"。

这可能吗?我该怎么做呢?

3 个答案:

答案 0 :(得分:3)

这就是你想要的吗?

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(delayExecuteMethod) object:nil];
[self performSelector:@selector(delayExecuteMethod) withObject:nil afterDelay:0.1];

答案 1 :(得分:0)

我写了一个类别来处理这个问题

NSObject+XLCDelayedPerform.h

#import <Foundation/Foundation.h>

@interface NSObject (XLCDelayedPerform)

- (void)xlc_setNeedsPerformSelector:(SEL)selector withObject:(id)obj;
- (void)xlc_setNeedsPerformSelector:(SEL)selector withObject:(id)obj withinInterval:(NSTimeInterval)interval;
- (void)xlc_performSelectorIfNeeded:(SEL)selector;

@end

NSObject+XLCDelayedPerform.m

#import "NSObject+XLCDelayedPerform.h"

#import <objc/runtime.h>

@implementation NSObject (XLCDelayedPerform)

static const void *delayedPerformInfoKey = &delayedPerformInfoKey;

- (void)xlc_setNeedsPerformSelector:(SEL)selector withObject:(id)obj {
    [self xlc_setNeedsPerformSelector:selector withObject:obj withinInterval:0];
}

- (void)xlc_setNeedsPerformSelector:(SEL)selector withObject:(id)obj withinInterval:(NSTimeInterval)interval {
    NSMutableDictionary *dict = objc_getAssociatedObject(self, delayedPerformInfoKey);
    if (!dict) {
        dict = [NSMutableDictionary dictionary];
        objc_setAssociatedObject(self, delayedPerformInfoKey, dict, OBJC_ASSOCIATION_RETAIN);
    }
    NSString *strSel = NSStringFromSelector(selector);
    id key = obj ? @[strSel, obj] : @[strSel];
    NSTimer *timer = dict[key];
    if (!timer) {
        timer = [NSTimer scheduledTimerWithTimeInterval:interval
                                                 target:self
                                               selector:@selector(xlc_delayedPerformSelectorOnTimer:)
                                               userInfo:key
                                                repeats:NO];
        dict[key] = timer;
    }
}

- (void)xlc_performSelectorIfNeeded:(SEL)selector {
    NSMutableDictionary *dict = objc_getAssociatedObject(self, delayedPerformInfoKey);
    NSString *strSel = NSStringFromSelector(selector);
    NSTimer *timer = dict[strSel];
    [timer fire];
}

#pragma mark - private

- (void)xlc_delayedPerformSelectorOnTimer:(NSTimer *)timer {
    NSArray *info = timer.userInfo;

    NSMutableDictionary *dict = objc_getAssociatedObject(self, delayedPerformInfoKey);
    [dict removeObjectForKey:info];

    id arg = info.count == 1 ? nil : info[1];

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    [self performSelector:NSSelectorFromString(info[0]) withObject:arg];
#pragma clang diagnostic pop
}

@end

例如

id obj = // something;
[obj xlc_setNeedsPerformSelector:@selector(dowork) withObject:nil];
[obj xlc_setNeedsPerformSelector:@selector(dowork) withObject:nil];

// [obj dowork] is called once on next runloop 

答案 2 :(得分:0)

我不确定您正在寻找什么样的界面,但使用私人队列和计数器应该允许您构建这种控件。这是一种概念验证。您必须修改程序以适合您的具体情况。

void coalesce_execution(dispatch_block_t executable,
                         dispatch_queue_t execution_queue,
                         double wait_interval)
{
    // Create a counter and a queue to synchronize access to it
    static unsigned int num_waiting = 0;
    static dispatch_queue_t wait_queue;
    static dispatch_once_t once_token;
    dispatch_once(&once_token, ^{
        wait_queue = dispatch_queue_create("your.label.here",
                                           DISPATCH_QUEUE_PRIORITY_DEFAULT);
    });

    // Increment shared counter on queue
    dispatch_async(wait_queue, ^{
        num_waiting++;
    });

    // Wait, then decrement counter on queue
    dispatch_time_t wait_time = dispatch_time(DISPATCH_TIME_NOW,
                                              (int64_t)(wait_interval * NSEC_PER_SEC));
    dispatch_after(wait_time, wait_queue, ^(void){
        num_waiting--;
        // If counter is zero, execute: nothing else came within the cutoff.
        if( 0 == num_waiting ){
            dispatch_async(execution_queue, executable);
        }
    });
}

按下这样的按钮:

- (IBAction)executeCoalescing:(id)sender 
{

    NSLog(@"Clicked.");
    coalesce_executions(^{ NSLog(@"Got through");  },
                        dispatch_get_main_queue(), 0.5);

}

按以下方式给出输出:

  

2014-06-04 03:40:33.374 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:33.565 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:34.066 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:34.600 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:34.802 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:35.304 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:35.342 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:35.623 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:36.085 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:36.585 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:40.955 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:41.135 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:41.315 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:41.518 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:41.698 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:41.878 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:42.047 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:42.238 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:42.429 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:42.598 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:42.789 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:42.980 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:43.482 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:44.894 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:45.395 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:46.0​​19 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:46.520 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:48.054 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:48.346 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:48.847 CoalesceExecutions [98519:303]通过了   2014-06-04 03:40:49.055 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:49.336 CoalesceExecutions [98519:303]点击。
  2014-06-04 03:40:49.837 CoalesceExecutions [98519:303]通过