43

我希望能够在未来安排三个小事件,而不必为每个事件编写一个函数。我怎样才能做到这一点NSTimer?我理解块有助于匿名函数,但它们可以在内部使用NSTimer吗?如果可以,如何使用?

[NSTimer scheduledTimerWithTimeInterval:gameInterval  
         target:self selector:@selector(/* I simply want to update a label here */) 
         userInfo:nil repeats:NO];
4

9 回答 9

57

如果您想实现类似于 NSTimer 的功能并阻止执行,则可以使用 dispatch_after。

这是相同的示例代码:

    int64_t delayInSeconds = gameInterval; // Your Game Interval as mentioned above by you

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

        // Update your label here. 

    });

希望这可以帮助。

于 2013-02-17T19:11:38.157 回答
29

您实际上可以调用:

NSTimer.scheduledTimerWithTimeInterval(ti: NSTimeInterval,
                    target: AnyObject, 
                    selector: #Selector, 
                    userInfo: AnyObject?, 
                    repeats: Bool)

像这样使用它:

NSTimer.scheduledTimerWithTimeInterval(1, 
                    target: NSBlockOperation(block: {...}), 
                    selector: #selector(NSOperation.main), 
                    userInfo: nil, 
                    repeats: true)

于 2016-05-05T21:08:43.710 回答
17

Cocoa 中存在基于块的计时器 API(从 iOS 10+ / macOS 10.12+ 开始) - 以下是从 Swift 3 开始使用它的方法:

Timer(timeInterval: gameInterval, repeats: false) { _ in
    print("herp derp")
}

… 或在 Objective-C 中:

[NSTimer scheduledTimerWithTimeInterval:gameInterval repeats:NO block:^(NSTimer *timer) {
    NSLog(@"herp derp");
}];

如评论中所述,请注意不要在块内使用强自引用以避免保留循环(更多信息)。

如果您需要针对早于 iOS10、macOS 12、tvOS 10、watchOS 3 的操作系统版本,您应该使用其他解决方案之一。

于 2016-10-25T15:09:12.263 回答
9

@Peter Peng 答案的 Objective-C 版本:

_actionDelayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"Well this is useless.");
}] selector:@selector(main) userInfo:nil repeats:YES];
于 2016-08-10T21:55:35.313 回答
6

这很容易,但它不包含在 Apple 框架中,至少目前还没有。

您可以为自己编写一个基于块的包装器NSTimer,例如使用GCD,或者您可以使用现有的第 3 方库,例如:https ://github.com/jivadevoe/NSTimer-Blocks 。

于 2013-02-17T19:12:52.673 回答
3

我在 NSTimer 上创建了一个类别,可以将其与块一起使用。

https://github.com/mBrissman/NSTimer-Block

于 2014-12-05T23:47:35.897 回答
2

截至 2018 年底,您完全可以这样做:

Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { timer in
  print("no, seriously, this works on iPhone")
} 

这要感谢@JohnnyC!

真是奇怪!

在此处输入图像描述

于 2018-12-21T20:53:40.260 回答
0

我已经制作了一个宏来执行此操作并自动处理 dealloc、arc、retain 循环等。无需担心使用弱引用。它也将始终在主线程上

#define inlineTimer(__interval, __block) {\
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.0) * NSEC_PER_SEC)), dispatch_get_main_queue(), (__block));\
[NSTimer scheduledTimerWithTimeInterval:__interval repeats:YES block:^(NSTimer *__timer) {\
if (self.window != nil) {\
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.0) * NSEC_PER_SEC)), dispatch_get_main_queue(), (__block));\
} else {\
[__timer invalidate];\
}\
}];\
}

示例用法:

__block ticks = 0;

inlineTimer(0.5, ^{
    ticks++;
    self.label.text = [NSString stringWithFormat:@"Ticks: %i", ticks];//strong reference to self and self.label won't cause retain cycle! Wahoo
});

请注意 self.label 不是弱引用,但由于宏的结构,这一切都会自动释放。

当然,这仅适用于 UI 类,因为它正在检查 .window 何时应该解除分配。

于 2020-08-11T06:15:59.123 回答
0

我喜欢这个黑客@Peter-Pang!BlockOperation 是动态创建的,由运行队列拥有的 Timer 拥有,并调用块上的主选择器来运行它....好!!!

更新为Swift 3

Timer.scheduledTimer(timeInterval: 1, target: BlockOperation { // ... }, selector: #selector(Operation.main), userInfo: nil, repeats: false)

于 2017-03-14T15:16:34.917 回答