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.
这里有很多错误:
Selector(executeCustomScheduler(nextTimeIndex))
根据执行一次executeCustomScheduler(nextTimeIndex)
的return值创建选择器
withObject: self
- 你为什么要通过 self
?
- 你为什么要使用
performSelector
?
executionTimes
不是以毫秒为单位而是以秒为单位,或者至少该方法期望它们是
- 最后一个问题:你的参数是一个原始的 Int,在
performSelector
中传递它时真的很麻烦
解决方案:
Selector("executeCustomScheduler:")
是正确的选择器
nextTimeIndex
是传递的正确参数
- 使用类型安全性更高的东西可能会更好,任何带有选择器的东西都容易出现大量关于重命名的问题,例如
- 将值除以 1000,然后将它们传递到
performSelector
- 我真的没有好的解决方案:最简单也可能是最糟糕的解决方案:使用
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);
}
我有一个包含以毫秒为单位的时间值的数组,例如:
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.
这里有很多错误:
Selector(executeCustomScheduler(nextTimeIndex))
根据执行一次executeCustomScheduler(nextTimeIndex)
的return值创建选择器withObject: self
- 你为什么要通过self
?- 你为什么要使用
performSelector
? executionTimes
不是以毫秒为单位而是以秒为单位,或者至少该方法期望它们是- 最后一个问题:你的参数是一个原始的 Int,在
performSelector
中传递它时真的很麻烦
解决方案:
Selector("executeCustomScheduler:")
是正确的选择器nextTimeIndex
是传递的正确参数- 使用类型安全性更高的东西可能会更好,任何带有选择器的东西都容易出现大量关于重命名的问题,例如
- 将值除以 1000,然后将它们传递到
performSelector
- 我真的没有好的解决方案:最简单也可能是最糟糕的解决方案:使用
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);
}