如何在延迟后触发块,如-performSelector:withObject:afterDelay:?

有没有办法在延迟之后调用一个带有基本参数的块,比如使用performSelector:withObject:afterDelay:但是使用像int / double / float这样的参数?

我想你正在寻找dispatch_after() 。 它要求您的块不接受任何参数,但是您可以让块从您的本地范围捕获这些variables。

 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_after来调用块。 在Xcode中,开始inputdispatch_after并按Enter自动完成以下内容:

在这里输入图像描述

这里有一个以两个浮点数作为“参数”的例子。 你不必依赖任何types的macros,代码的意图是非常明确的:

Swift 3,Swift 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)") } 

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

如何使用Xcode内置的代码片段库?

在这里输入图像描述

Swift更新:

许多投票激励我更新这个答案。

内置的Xcode代码片段库仅针对objective-c语言具有dispatch_after 。 人们也可以为Swift创build自己的自定义代码片段

写在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#> }) 

将此代码拖放到代码段库区域中。 在这里输入图像描述

在代码片段列表的底部,将会有一个名为My Code Snippet的新实体。 编辑这个标题。 对于在Xcode中input的build议,填写Completion Shortcut

有关更多信息,请参阅CreatingaCustomCodeSnippet 。

更新Swift 3

将此代码拖放到代码段库区域中。

 DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) { <#code to be executed after a specified delay#> } 

扩展Jaime Cham的答案我创build了一个NSObject + Blocks类别如下。 我觉得这些方法更符合现有的performSelector: NSObject方法

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]; 

对于Swift,我使用dispatch_after方法创build了一个全局函数,没有什么特别的。 我更喜欢这个,因为它是可读的,易于使用:

 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) 

也许比通过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!"); }]; 

这是我的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); } 

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:]等….在接收方法,你可以转换为您的格式为[数字整数]或[数字双]的数字。

dispatch_after函数在给定的时间段之后调度一个块对象到一个调度队列。 使用下面的代码在2.0秒后执行一些与UI有关的taks。

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

在迅速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: { }) 

这是Swift 3延迟排队工作的方法。

 DispatchQueue.main.asyncAfter( DispatchTime.now() + DispatchTimeInterval.seconds(2)) { // do work } 

这里有一个方便的帮手来防止令人讨厌的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 } 

如果你更喜欢一个框架 ,也有一些更方便的function,然后检查HandySwift 。 您可以通过Carthage将其添加到您的项目中然后像上面的示例一样使用它:

 import HandySwift delay(bySeconds: 1.5) { // delayed code } 

BlocksKit框架中有一个很好的。

BlocksKit

(和class级)

BBlocksKit.m

在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 } 

您可以将参数包装在您自己的类中,也可以将方法调用包装在不需要以原始types传递的方法中。 然后在延迟后调用该方法,并在该方法内执行您希望执行的select器。

下面是如何在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) } 

它包含在我的回购标准function。

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

我相信作者并没有问如何等待分数时间(延迟),而是如何传递一个标量作为select器的参数(withObject :),而现代客观的C中最快的方法是:

 [obj performSelector:... withObject:@(0.123123123) afterDelay:10] 

你的select器必须改变其参数为NSNumber,并使用像floatValue或doubleValueselect器检索值

 [NSTimer scheduledTimerWithTimeInterval:2.5 target:self selector:@selector(toDoSomething) userInfo:nil repeats:NO];