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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:03:41  来源:igfitidea点击:

How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?

iosobjective-cgrand-central-dispatchobjective-c-blocks

提问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_afterto call a block later. In Xcode, start typing dispatch_afterand hit Enterto autocomplete to the following:

您可以使用dispatch_after稍后调用块。在 Xcode 中,开始输入dispatch_after并点击Enter自动完成以下内容:

enter image description here

在此处输入图片说明

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 内置的代码片段库?

enter image description here

在此处输入图片说明

Update for Swift:

Swift 更新:

Many up votes inspired me to update this answer.

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

The build-in Xcode code snippet library has dispatch_afterfor only objective-clanguage. 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. enter image description here

将此代码拖放到代码片段库区域中。 在此处输入图片说明

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_aftermethod. 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
}