iOS: 如何在不同(定义的)时间后顺序调用函数?

iOS: How to call a function sequentially after different (defined) amount of time?

我有一个包含以毫秒为单位的时间值的数组,例如:

let executionTimes = [0, 1500, 3500, 4700]

最上面有一个函数可以简单地做任何事情 - 现在 - 打印一些文本:

func printHello() {
    print("Hello")
}

我想做的是在数组中的给定时间段后执行函数。所以 printHello() 将立即执行,然后在 1.5 秒后,再过 2 秒后,最后再过 1.2 秒,然后再次从头开始。现在我希望这个函数调用的时间继续 "forever"。

首先,我尝试使用 NSTimer 来解决这个问题,但从我发现的情况来看,如果不首先使其失效,就不可能动态更改计时器的 timeInterval,这会随着给定的时间表而缓和。

然后我认为使用 performSelector 可以解决这个问题:

func executeCustomScheduler(timeIndex: Int) {
    let time: Double = executionTimes[timeIndex]

    NSLog("Hello")

    let nextTimeIndex = timeIndex == (executionTimes.count - 1) ? 0 : timeIndex + 1

    self.performSelector(Selector(executeCustomScheduler(nextTimeIndex)), withObject: self, afterDelay: time)
}

这根本不起作用,因为函数的执行完全没有延迟,并且由于我认为的递归调用而崩溃。

任何人都可以提供任何有用的提示吗?

非常感谢!

您可以为此使用 NSTimer

NSDate *date = [[NSDate date] dateByAddingTimeInterval:someInterval];
NSTimer *timer = [[NSTimer alloc] initWithFireDate:date interval:0 target:self selector:@selector(timerFired:) userInfo:info repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

这样,您可以将时间间隔添加到日期中,并安排计时器(是的,每个时间间隔都有很多)在那个时间触发。希望这可以帮助。此外,如果您以后想 invalidate 定时器,则应该将定时器保存在某个数组中。祝你好运!

PS。对不起 objective c 的东西,希望你能把它转换成 swift.

这里有很多错误:

  1. Selector(executeCustomScheduler(nextTimeIndex))根据执行一次executeCustomScheduler(nextTimeIndex)的return值创建选择器
  2. withObject: self - 你为什么要通过 self
  3. 你为什么要使用 performSelector
  4. executionTimes 不是以毫秒为单位而是以秒为单位,或者至少该方法期望它们是
  5. 最后一个问题:你的参数是一个原始的 Int,在 performSelector
  6. 中传递它时真的很麻烦

解决方案:

  1. Selector("executeCustomScheduler:") 是正确的选择器
  2. nextTimeIndex 是传递的正确参数
  3. 使用类型安全性更高的东西可能会更好,任何带有选择器的东西都容易出现大量关于重命名的问题,例如
  4. 将值除以 1000,然后将它们传递到 performSelector
  5. 我真的没有好的解决方案:最简单也可能是最糟糕的解决方案:使用 String 而不是 Int :/

更好的解决方案:
使用 dispatch_after,摆脱那些讨厌的选择器并始终保持类型安全:

class Obj {

    let executionTimes = [0, 1500, 3500, 4700]

    func executeCustomScheduler(timeIndex: Int) {
        NSLog("Hello")

        let time = executionTimes[timeIndex]
        let nextTimeIndex = (timeIndex + 1) % executionTimes.count

        let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(Double(time) / 1000 * Double(NSEC_PER_SEC)))
        dispatch_after(delayTime, dispatch_get_main_queue()) {
            self.executeCustomScheduler(nextTimeIndex)
        }
    }
}

let obj = Obj()
obj.executeCustomScheduler(0)

您不必使用我们 NSTimer 来实现您想要的。其实解决你的问题很简单。

Swift中的示例解决方案:

let executionTimes = [1000.0, 1500.0, 3500.0, 4700.0]

for executionTime in executionTimes {
    self.performSelector(#selector(printHello(_:)), withObject: NSNumber(double: executionTime), afterDelay: executionTime/1000.0)
}

func printHello(executionTime: NSNumber) {
     let doubleValue = executionTime.doubleValue
     print("Hello \(doubleValue)")
}

请注意,您不能将结构作为标有 withObject: 标签的参数传递。这就是为什么我用 NSNumber(这是一个 class)包装 Double(这是一个结构)实例。

Objective-c中的示例解决方案:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    NSArray<NSNumber *> *executionTimes = @[@(1000.0), @(1500.0), @(3500.0), @(4700.0)];
    for (NSNumber *executionTime in executionTimes) {
        [self performSelector:@selector(printHello:) withObject:executionTime afterDelay:executionTime.doubleValue/1000];
    }

    return YES;
}

- (void)printHello:(NSNumber *)executionTime
{
    NSLog(@"Hello %@", executionTime.stringValue);
}