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

时间:2016-04-16 09:38:17

标签: ios swift nstimer performselector

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

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

最重要的是,有一个功能只是做任何事情 - 现在 - 打印一些文字:

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

我想要做的是在数组中给定的时间段后执行该函数。因此,printHello()将立即执行,然后在1.5秒后执行,然后再执行2秒,最后再执行1,2秒,然后再从开始执行。现在我希望这个函数调用时间能够“永远”继续。

首先我尝试使用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)
}

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

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

非常感谢!

3 个答案:

答案 0 :(得分:0)

您可以使用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。抱歉,客观的事情,希望你能把它转换成swift。

答案 1 :(得分:0)

这里有很多错误:

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

    解决方案:

    1. Selector("executeCustomScheduler:")是正确的选择器
    2. nextTimeIndex是传递
    3. 的正确参数
    4. 使用具有更多类型安全性的东西可能会更好,任何带有选择器的东西都可以解决大量有关重命名的问题。
    5. 在将值传递到performSelector
    6. 之前将值除以1000
    7. 我真的没有一个好的解决方案:最简单也可能最差的一个:使用String代替Int:/
    8. 更好的解决方案:
      使用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)
      

答案 2 :(得分: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)")
}

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

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);
}