performSelector:withObject:afterDelay:
一样,但参数是像 int
/double
/float
这样的类型?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_after
延迟调用一个block。在Xcode中,打开代码自动完成并输入dispatch_after
后按Enter
键即可自动补全如下代码:
下面是一个具有两个浮点数“参数”的示例。你不需要依赖任何宏定义,代码的意图非常清晰:
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
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)")
}
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
需要一个64位整数,但它所需的值是以纳秒为单位的。NSEC_PER_SEC
被定义为 1000000000ull
,将其乘以浮点常量 0.5
将隐式执行浮点运算,得到 500000000.0
,然后再明确地转换回一个64位整数。因此,使用 NSEC_PER_SEC
的一部分是完全可以接受的。 - junjie如何使用Xcode内置的代码片段库?
适用于Swift:
许多赞鼓舞了我更新这个答案。
Xcode内置的代码片段库只有针对Objective-C
语言的dispatch_after
。人们也可以为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#>
})
在代码段列表底部,将会出现一个名为My Code Snippet
的新实体。编辑此实体以添加标题,并在Xcode中填写Completion Shortcut
以进行建议。
有关更多信息,请参见CreatingaCustomCodeSnippet。
将此代码拖动并放入代码段库区域。
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
<#code to be executed after a specified delay#>
}
根据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];
NSTimeInterval
(即double
)。不需要导入<UIKit/UIKit.h>
。而且,我不认为- (void)performBlock:(void (^)())block;
有用,因此可以从头文件中删除。 - meaning-matters也许比通过GCD更简单的方法是,在某个类中(例如“Util”)或Object的类别中:
+ (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!");}];
对于Swift,我创建了一个全局函数,没有什么特别的,使用了dispatch_after
方法。我更喜欢这种方式,因为它更易读和使用:
对于 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)
这是我的个人意见 = 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 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
});
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")
})
在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)
。 - BastianPerformSelector: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] ];
}
dispatch_time(DISPATCH_TIME_NOW, 10ull * NSEC_PER_SEC)
的片段很糟糕。难道没有更简洁的方式吗? - samvermettedispatch_get_current_queue()
总是返回正在运行代码的队列。因此,当该代码在主线程上运行时,这个块也将在主线程上执行。 - Ryandispatch_get_current_queue()
现已被弃用。 - Matej