Objective C for循环延迟
Objective C for loop delay
我有一个 for 循环,我想在迭代之间添加延迟。我已将 waitUntilDone 更改为 YES 并获得相同的结果。我的数组中只有两个数字,并且都在五秒后被调用,而不是:
0s - 没有
5s - 块叫
10s- 区块调用
for(NSNumber* transaction in gainsArray) {
double delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSLog(@"Block");
[self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:)
withObject:transaction waitUntilDone:NO];
});
}
2015-06-16 20:11:06.485 TestApp[97027:6251126] Block
2015-06-16 20:11:06.485 TestApp[97027:6251127] Block
如果重要的话,我正在使用 Cocos2d
for 循环将一个接一个地调度,因此它们基本上会延迟相同的时间。
而是为每个设置不同的递增延迟:
double delayInSeconds = 0.0;
for(NSNumber* transaction in gainsArray)
{
delayInSeconds += 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
NSLog(@"Block");
[self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:)
withObject:transaction
waitUntilDone:NO];
});
}
@zaph 有一个很好的解决方案。我想我会从不同的角度尝试。由于 Objective-C 是 Objective-C,为什么不定义某种对象来执行此定时循环?提示:这是存在的。我们可以使用 NSTimer 及其 userInfo 属性 来解决这个问题。我认为解决方案有点优雅,即使不是令人讨厌的 hack。
// Somewhere in code.... to start the 'loop'
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
action:@selector(processNextTransaction:)
userInfo:@{
@"gains": [gainsArray mutableCopy]
}
repeats:NO];
// What handles each 'iteration' of your 'loop'
- (void)processNextTransaction:(NSTimer *)loopTimer {
NSMutableArray *gains = [loopTimer.userInfo objectForKey:@"gains"];
if(gains && gains.count > 0) {
id transaction = [gains firstObject];
[gains removeObjectAtIndex:0]; // NSMutableArray should really return the object we're removing, but it doesn't...
[self private_addTransactionToBankroll:transaction];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
action:@selector(processNextTransaction:)
userInfo:@{
@"gains": gains
}
repeats:NO];
}
}
我会通过将 NSTimer 添加到 运行 循环来检查是否保留了它。如果不是这种情况,您应该将对它的引用存储为 属性 在 class 管理所有这些的任何东西上。
还值得注意的是,因为默认情况下 NSTimers 安装在主 运行 循环中,所以您无需担心所有 GCD 内容。话又说回来,如果这项工作是相当困难的工作,您可能希望 -processNextTransaction:
将其工作卸载到另一个 GCD 队列,然后返回到主队列来初始化 NSTimer 实例。
一定要使用-scheduledTimer...
方法; timer...
class NSTimer
上的方法不会将其安装在任何循环中,对象只是坐在 space 中什么都不做。不要做 repeats:YES
,那将是悲剧性的,因为您会随意地将计时器附加到 运行 循环,而没有指向它们的引用以知道如何或在何处停止它们。这通常是一件坏事。
为避免 EXC_BAD_ACCESS
异常,永远不要释放 NSTimer
将调用其方法的对象,如果该计时器尚未触发。您可能希望将待处理的 NSTimer
存储在 class 上的 属性 中,以便您可以处理此类事情。如果是 ViewController 管理所有这些(通常是这样),那么我将使用以下代码清理 -viewWillDisappear
上的计时器。 (假设您将新计时器设置为 @property
、self.timer
)
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if(self.timer) {
[self.timer invalidate]; // -invalidate removes it from the run loop.
self.timer = nil; // Stop pointing at it so ARC destroys it.
}
}
我有一个 for 循环,我想在迭代之间添加延迟。我已将 waitUntilDone 更改为 YES 并获得相同的结果。我的数组中只有两个数字,并且都在五秒后被调用,而不是:
0s - 没有 5s - 块叫 10s- 区块调用
for(NSNumber* transaction in gainsArray) {
double delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSLog(@"Block");
[self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:)
withObject:transaction waitUntilDone:NO];
});
}
2015-06-16 20:11:06.485 TestApp[97027:6251126] Block
2015-06-16 20:11:06.485 TestApp[97027:6251127] Block
如果重要的话,我正在使用 Cocos2d
for 循环将一个接一个地调度,因此它们基本上会延迟相同的时间。
而是为每个设置不同的递增延迟:
double delayInSeconds = 0.0;
for(NSNumber* transaction in gainsArray)
{
delayInSeconds += 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
{
NSLog(@"Block");
[self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:)
withObject:transaction
waitUntilDone:NO];
});
}
@zaph 有一个很好的解决方案。我想我会从不同的角度尝试。由于 Objective-C 是 Objective-C,为什么不定义某种对象来执行此定时循环?提示:这是存在的。我们可以使用 NSTimer 及其 userInfo 属性 来解决这个问题。我认为解决方案有点优雅,即使不是令人讨厌的 hack。
// Somewhere in code.... to start the 'loop'
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
action:@selector(processNextTransaction:)
userInfo:@{
@"gains": [gainsArray mutableCopy]
}
repeats:NO];
// What handles each 'iteration' of your 'loop'
- (void)processNextTransaction:(NSTimer *)loopTimer {
NSMutableArray *gains = [loopTimer.userInfo objectForKey:@"gains"];
if(gains && gains.count > 0) {
id transaction = [gains firstObject];
[gains removeObjectAtIndex:0]; // NSMutableArray should really return the object we're removing, but it doesn't...
[self private_addTransactionToBankroll:transaction];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
action:@selector(processNextTransaction:)
userInfo:@{
@"gains": gains
}
repeats:NO];
}
}
我会通过将 NSTimer 添加到 运行 循环来检查是否保留了它。如果不是这种情况,您应该将对它的引用存储为 属性 在 class 管理所有这些的任何东西上。
还值得注意的是,因为默认情况下 NSTimers 安装在主 运行 循环中,所以您无需担心所有 GCD 内容。话又说回来,如果这项工作是相当困难的工作,您可能希望 -processNextTransaction:
将其工作卸载到另一个 GCD 队列,然后返回到主队列来初始化 NSTimer 实例。
一定要使用-scheduledTimer...
方法; timer...
class NSTimer
上的方法不会将其安装在任何循环中,对象只是坐在 space 中什么都不做。不要做 repeats:YES
,那将是悲剧性的,因为您会随意地将计时器附加到 运行 循环,而没有指向它们的引用以知道如何或在何处停止它们。这通常是一件坏事。
为避免 EXC_BAD_ACCESS
异常,永远不要释放 NSTimer
将调用其方法的对象,如果该计时器尚未触发。您可能希望将待处理的 NSTimer
存储在 class 上的 属性 中,以便您可以处理此类事情。如果是 ViewController 管理所有这些(通常是这样),那么我将使用以下代码清理 -viewWillDisappear
上的计时器。 (假设您将新计时器设置为 @property
、self.timer
)
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if(self.timer) {
[self.timer invalidate]; // -invalidate removes it from the run loop.
self.timer = nil; // Stop pointing at it so ARC destroys it.
}
}