ios 如何在延迟后触发块,例如 -performSelector:withObject:afterDelay:?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4139219/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?
提问by Egil
Is there a way to call a block with a primitive parameter after a delay, like using performSelector:withObject:afterDelay:
but with an argument like int
/double
/float
?
有没有一种方法来调用与原始参数块的延迟之后,就像使用performSelector:withObject:afterDelay:
但像参数int
/ double
/ float
?
回答by Ryan
I think you're looking for dispatch_after()
. It requires your block to accept no parameters, but you can just let the block capture those variables from your local scope instead.
我想你正在寻找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);
});
More: https://developer.apple.com/documentation/dispatch/1452876-dispatch_after
更多:https: //developer.apple.com/documentation/dispatch/1452876-dispatch_after
回答by Steven Hepting
You can use dispatch_after
to call a block later. In Xcode, start typing dispatch_after
and hit Enter
to autocomplete to the following:
您可以使用dispatch_after
稍后调用块。在 Xcode 中,开始输入dispatch_after
并点击Enter
自动完成以下内容:
Here's an example with two floats as "arguments." You don't have to rely on any type of macro, and the intent of the code is quite clear:
这是一个使用两个浮点数作为“参数”的示例。您不必依赖任何类型的宏,代码的意图非常明确:
Swift 3, Swift 4
斯威夫特 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)")
}
Swift 2
斯威夫特 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)")
}
Objective C
目标 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);
});
回答by Warif Akhand Rishi
How about using Xcode built-in code snippet library?
如何使用 Xcode 内置的代码片段库?
Update for Swift:
Swift 更新:
Many up votes inspired me to update this answer.
许多投票激励我更新这个答案。
The build-in Xcode code snippet library has dispatch_after
for only objective-c
language. People can also create their own Custom Code Snippetfor Swift
.
内置的 Xcode 代码片段库dispatch_after
仅适用于objective-c
语言。人们还可以创建自己的自定义代码段的Swift
。
Write this in Xcode.
用 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#>
})
Drag this code and drop it in the code snippet library area.
Bottom of the code snippet list, there will be a new entity named My Code Snippet
. Edit this for a title. For suggestion as you type in the Xcode fill in the Completion Shortcut
.
在代码片段列表的底部,会有一个名为 的新实体My Code Snippet
。编辑此标题。对于在 Xcode 中键入时的建议,请填写Completion Shortcut
.
For more info see CreatingaCustomCodeSnippet.
有关更多信息,请参阅CreatingaCustomCodeSnippet。
Update Swift 3
更新 Swift 3
Drag this code and drop it in the code snippet library area.
将此代码拖放到代码片段库区域中。
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
<#code to be executed after a specified delay#>
}
回答by Oliver Pearmain
Expanding on Jaime Cham's answer I created a NSObject+Blocks category as below. I felt these methods better matched the existing performSelector:
NSObject methods
扩展 Jaime Cham 的回答,我创建了一个 NSObject+Blocks 类别,如下所示。我觉得这些方法更适合现有的performSelector:
NSObject 方法
NSObject+Blocks.h
NSObject+Blocks.h
#import <Foundation/Foundation.h>
@interface NSObject (Blocks)
- (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay;
@end
NSObject+Blocks.m
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
and use like so:
并像这样使用:
[anyObject performBlock:^{
[anotherObject doYourThings:stuff];
} afterDelay:0.15];
回答by Jaime Cham
Perhaps simpler than going thru GCD, in a class somewhere (e.g. "Util"), or a Category on Object:
也许比通过 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];
}
So to use:
所以要使用:
[Util runAfterDelay:2 block:^{
NSLog(@"two seconds later!");
}];
回答by Antoine
For Swift I've created a global function, nothing special, using the dispatch_after
method. I like this more as it's readable and easy to use:
对于 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)
}
Which you can use as followed:
您可以按如下方式使用:
performBlock({ () -> Void in
// Perform actions
}, afterDelay: 0.3)
回答by Dan Rosenstark
Here are my 2 cents = 5 methods ;)
这是我的 2 美分 = 5 种方法;)
I like encapsulate these details and have AppCode tell me how to finish my sentences.
我喜欢封装这些细节,让 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);
}
回答by Himanshu Mahajan
The dispatch_after function dispatches a block object to a dispatch queue after a given period of time. Use below code to perform some UI related taks after 2.0 seconds.
dispatch_after 函数在给定的时间段后将块对象分派到分派队列。使用下面的代码在 2.0 秒后执行一些与 UI 相关的任务。
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")
})
In swift 3.0 :
在 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: {
})
回答by Augustine
PerformSelector:WithObject always takes an object, so in order to pass arguments like int/double/float etc..... You can use something like this.
PerformSelector:WithObject始终以一个对象,所以为了通过如int /双/浮法等等.....您可以使用类似这样的论点。
//NSNumber is an object..
//NSNumber 是一个对象..
[self performSelector:@selector(setUserAlphaNumber:)
withObject: [NSNumber numberWithFloat: 1.0f]
afterDelay:1.5];
-(void) setUserAlphaNumber: (NSNumber*) number{
[txtUsername setAlpha: [number floatValue] ];
}
Same way you can use [NSNumber numberWithInt:] etc.... and in the receiving method you can convert the number into your format as [number int] or [number double].
同样的方式你可以使用 [NSNumber numberWithInt:] 等......并且在接收方法中你可以将数字转换为你的格式 [number int] 或 [number double]。
回答by Jeehut
Here's a handy helperto prevent making the annoying GCD callover and over again:
这是一个方便的助手,可以防止一遍又一遍地进行烦人的 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)
}
}
}
Now you simply delay your code on the Main threadlike this:
现在你只需像这样在主线程上延迟你的代码:
delay(bySeconds: 1.5) {
// delayed code
}
If you want to delay your code to different thread:
如果您想将代码延迟到不同的线程:
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
If you prefer a Frameworkthat also has some more handy features then checkout HandySwift. You can add it to your project via Carthagethen use it exactly like in the examples above:
如果您更喜欢具有更多方便功能的框架,请查看 HandySwift。你可以通过 Carthage将它添加到你的项目中,然后像上面的例子一样使用它:
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}