提问人:Egil 提问时间:11/10/2010 最后编辑:Leo DabusEgil 更新时间:12/30/2022 访问量:396615
如何在延迟后触发块,例如 -performSelector:withObject:afterDelay:?
How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?
问:
有没有办法在延迟后使用原始参数调用块,例如使用 但使用类似 // 的参数?performSelector:withObject:afterDelay:
int
double
float
答:
可以将参数包装在自己的类中,也可以将方法调用包装在不需要在基元类型中传递的方法中。然后在延迟后调用该方法,并在该方法中执行要执行的选择器。
我想你正在寻找.它要求您的模块不接受任何参数,但您可以让模块从本地范围捕获这些变量。dispatch_after()
int parameter1 = 12;
float parameter2 = 144.1;
// Delay execution of my block for 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSLog(@"parameter1: %d parameter2: %f", parameter1, parameter2);
});
更多: https://developer.apple.com/documentation/dispatch/1452876-dispatch_after
评论
dispatch_time(DISPATCH_TIME_NOW, 10ull * NSEC_PER_SEC)
dispatch_get_current_queue()
dispatch_get_current_queue()
现已弃用
也许比通过 GCD 更简单,在某个地方的类中(例如“Util”),或者在对象上的类别中:
+ (void)runBlock:(void (^)())block
{
block();
}
+ (void)runAfterDelay:(CGFloat)delay block:(void (^)())block
{
void (^block_)() = [[block copy] autorelease];
[self performSelector:@selector(runBlock:) withObject:block_ afterDelay:delay];
}
所以要使用:
[Util runAfterDelay:2 block:^{
NSLog(@"two seconds later!");
}];
评论
您可以稍后使用来调用块。在 Xcode 中,开始键入并点击自动完成以下内容:dispatch_after
dispatch_after
Enter
下面是一个将两个浮点数作为“参数”的示例。您不必依赖任何类型的宏,并且代码的意图非常明确:
斯威夫特 3、斯威夫特 4
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
斯威夫特 2
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
println("Sum of times: \(time1 + time2)")
}
目标 C
CGFloat time1 = 3.49;
CGFloat time2 = 8.13;
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat newTime = time1 + time2;
NSLog(@"New time: %f", newTime);
});
评论
NSEC_PER_SEC * 0.5
NSEC_PER_MSEC * 500
dispatch_time
NSEC_PER_SEC
1000000000ull
0.5
500000000.0
NSEC_PER_SEC
BlocksKit 框架中有一个很好的。
(和班级)
根据 Jaime Cham 的回答,我创建了一个 NSObject+Blocks 类别,如下所示。我觉得这些方法与现有的 NSObject 方法更匹配performSelector:
NSObject+Blocks.h
#import <Foundation/Foundation.h>
@interface NSObject (Blocks)
- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay;
@end
NSObject+Blocks.m
#import "NSObject+Blocks.h"
@implementation NSObject (Blocks)
- (void)performBlock:(void (^)())block
{
block();
}
- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay
{
void (^block_)() = [block copy]; // autorelease this if you're not using ARC
[self performSelector:@selector(performBlock:) withObject:block_ afterDelay:delay];
}
@end
并像这样使用:
[anyObject performBlock:^{
[anotherObject doYourThings:stuff];
} afterDelay:0.15];
评论
delay
NSTimeInterval
double
#import <UIKit/UIKit.h>
- (void)performBlock:(void (^)())block;
PerformSelector:WithObject 总是接受一个对象,因此为了传递 int/double/float 等参数.....你可以使用这样的东西。
NSNumber 是一个对象。
[self performSelector:@selector(setUserAlphaNumber:)
withObject: [NSNumber numberWithFloat: 1.0f]
afterDelay:1.5];
-(void) setUserAlphaNumber: (NSNumber*) number{
[txtUsername setAlpha: [number floatValue] ];
}
同样,您可以使用 [NSNumber numberWithInt:] 等。在接收方法中,您可以将数字转换为 [number int] 或 [number double] 格式。
这是我的 2 美分 = 5 种方法;)
我喜欢封装这些细节,并让 AppCode 告诉我如何完成我的句子。
void dispatch_after_delay(float delayInSeconds, dispatch_queue_t queue, dispatch_block_t block) {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, queue, block);
}
void dispatch_after_delay_on_main_queue(float delayInSeconds, dispatch_block_t block) {
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_after_delay(delayInSeconds, queue, block);
}
void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}
void dispatch_async_on_background_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}
void dispatch_async_on_main_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_main_queue(), block);
}
使用 Xcode 内置代码片段库怎么样?
Swift 更新:
许多赞成票激发了我更新这个答案。
内置的 Xcode 代码片段库仅包含语言。用户还可以为 创建自己的自定义代码片段。dispatch_after
objective-c
Swift
用 Xcode 编写此内容。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(<#delayInSeconds#> * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), {
<#code to be executed after a specified delay#>
})
在代码片段列表的底部,将有一个名为 的新实体。编辑标题。在键入 Xcode 时,请填写“完成快捷方式
”,以获取建议。My Code Snippet
有关更多信息,请参阅 CreatingaCustomCodeSnippet。
更新 Swift 3
将此代码拖放到代码片段库区域中。
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
<#code to be executed after a specified delay#>
}
评论
对于 Swift,我使用该方法创建了一个全局函数,没什么特别的。我更喜欢这个,因为它可读且易于使用:dispatch_after
func performBlock(block:() -> Void, afterDelay delay:NSTimeInterval){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), block)
}
您可以按如下方式使用:
performBlock({ () -> Void in
// Perform actions
}, afterDelay: 0.3)
评论
after
after(2.0){ print("do somthing") }
以下是在 Swift 延迟后触发阻塞的方法:
runThisAfterDelay(seconds: 2) { () -> () in
print("Prints this 2 seconds later in main queue")
}
/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), after)
}
它作为标准函数包含在我的 repo 中。
dispatch_after 函数在给定的时间段后将块对象分派到调度队列。使用以下代码在 2.0 秒后执行一些与 UI 相关的 tak。
let delay = 2.0
let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
let mainQueue = dispatch_get_main_queue()
dispatch_after(delayInNanoSeconds, mainQueue, {
print("Some UI related task after delay")
})
在 swift 3.0 中:
let dispatchTime: DispatchTime = DispatchTime.now() + Double(Int64(2.0 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: dispatchTime, execute: {
})
评论
mainQueue,
mainQueue)
这里有一个方便的助手,可以防止一遍又一遍地进行烦人的 GCD 调用:
public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
let dispatchTime = DispatchTime.now() + seconds
dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}
public enum DispatchLevel {
case main, userInteractive, userInitiated, utility, background
var dispatchQueue: DispatchQueue {
switch self {
case .main: return DispatchQueue.main
case .userInteractive: return DispatchQueue.global(qos: .userInteractive)
case .userInitiated: return DispatchQueue.global(qos: .userInitiated)
case .utility: return DispatchQueue.global(qos: .utility)
case .background: return DispatchQueue.global(qos: .background)
}
}
}
现在,您只需在主线程上延迟代码,如下所示:
delay(bySeconds: 1.5) {
// delayed code
}
如果要将代码延迟到其他线程:
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
如果您更喜欢具有一些更方便功能的框架,请查看 HandySwift。您可以通过 Carthage 将其添加到您的项目中,然后完全按照上面的示例使用它:
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
评论
这是 Swift 3 在延迟后排队工作的方法。
DispatchQueue.main.asyncAfter(
DispatchTime.now() + DispatchTimeInterval.seconds(2)) {
// do work
}
我相信作者不是在问如何等待小数时间(延迟),而是在问如何传递标量作为选择器的参数(withObject:),而现代目标 C 中最快的方法是:
[obj performSelector:... withObject:@(0.123123123) afterDelay:10]
您的选择器必须将其参数更改为 NSNumber,并使用 floatValue 或 doubleValue 等选择器检索值
在 swift 3 中,我们可以简单地使用 DispatchQueue.main.asyncAfter 函数在延迟 'n' 秒后触发任何函数或操作。在代码中,我们设置了 1 秒后的延迟。您调用此函数主体内的任何函数,该函数将在延迟 1 秒后触发。
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {
// Trigger the function/action after the delay of 1Sec
}
Swift 3 和 Xcode 8.3.2
这段代码会帮到你,我也添加一个解释
// Create custom class, this will make your life easier
class CustomDelay {
static let cd = CustomDelay()
// This is your custom delay function
func runAfterDelay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
}
// here how to use it (Example 1)
class YourViewController: UIViewController {
// example delay time 2 second
let delayTime = 2.0
override func viewDidLoad() {
super.viewDidLoad()
CustomDelay.cd.runAfterDelay(delayTime) {
// This func will run after 2 second
// Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
self.runFunc()
}
}
// example function 1
func runFunc() {
// do your method 1 here
}
}
// here how to use it (Example 2)
class YourSecondViewController: UIViewController {
// let say you want to user run function shoot after 3 second they tap a button
// Create a button (This is programatically, you can create with storyboard too)
let shootButton: UIButton = {
let button = UIButton(type: .system)
button.frame = CGRect(x: 15, y: 15, width: 40, height: 40) // Customize where do you want to put your button inside your ui
button.setTitle("Shoot", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
// create an action selector when user tap shoot button
shootButton.addTarget(self, action: #selector(shoot), for: .touchUpInside)
}
// example shoot function
func shoot() {
// example delay time 3 second then shoot
let delayTime = 3.0
// delay a shoot after 3 second
CustomDelay.cd.runAfterDelay(delayTime) {
// your shoot method here
// Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
}
}
}
Xcode 10.2 和 Swift 5 及更高版本
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
// code to execute
})
ObjC 版本
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
//code to execute
});
评论
2021 年 4 月更新了 Xcode 12.4。这仍然有效,只是现在按钮显示更多图标,包括视图库和修改器库(见下文),视图可能是默认值。因此,请务必选择 Snippets 库,如下图所示。+
(2020 年 6 月在 Xcode 11.3.1 上验证)
Xcode 提供了一个代码片段来执行此操作。您只需要输入延迟值和要在延迟后运行的代码。
- 单击 Xcode 右上角的按钮,同时编辑一些代码(而不是在项目导航器中,其中会显示其他库,如功能)
+
- 确保从可用的图标中选择了 Snippets 库(请参见屏幕截图,带有 { } 的图标)。
- 寻找
after
- 它将仅返回 1 个搜索结果,这是所需的片段(请参见屏幕截图)。双击它,你就可以开始了。
按 Cmd + Shift + L 显示 Xcode 内置代码片段库:
在之后查找调度,然后,只需拖放到您的代码中即可。
评论