Как вы запускаете блок после задержки, например -performSelector: withObject: afterDelay :? - PullRequest
718 голосов
/ 10 ноября 2010

Есть ли способ вызвать блок с параметром примитива после задержки, например, используя performSelector:withObject:afterDelay:, но с аргументом, подобным int / double / float?

Ответы [ 18 ]

1149 голосов
/ 10 ноября 2010

Я думаю, что вы ищете 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

484 голосов
/ 24 октября 2011

Вы можете использовать dispatch_after для последующего вызова блока. В Xcode начните вводить dispatch_after и нажмите Enter, чтобы автозаполнить следующее:

enter image description here

Вот пример с двумя числами с плавающей точкой в ​​качестве «аргументов». Вам не нужно полагаться на макросы любого типа, и цель кода совершенно ясна:

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);
});
192 голосов
/ 23 мая 2014

Как насчет использования встроенной библиотеки фрагментов кода Xcode?

enter image description here

Обновление для 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#>
    })

Перетащите этот код и поместите его в область библиотеки фрагментов кода.enter image description here

Внизу списка фрагментов кода появится новый объект с именем My Code Snippet.Отредактируйте это для заголовка.Для предложения при вводе в Xcode заполните Completion Shortcut.

Для получения дополнительной информации см. СозданиеaCustomCodeSnippet .

Обновление Swift 3

Перетащите этот код в область библиотеки фрагментов кода.

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
    <#code to be executed after a specified delay#>
}
57 голосов
/ 12 февраля 2013

В продолжение ответа Хайме Чама я создал категорию 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];
21 голосов
/ 27 сентября 2011

Возможно, проще, чем проходить через 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!");
}];
21 голосов
/ 08 апреля 2015

Для 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)
16 голосов
/ 25 февраля 2014

Вот мои 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);
}
8 голосов
/ 21 января 2016

Функция dispatch_after отправляет объект блока в очередь отправки по истечении заданного периода времени. Используйте приведенный ниже код для выполнения некоторых связанных с пользовательским интерфейсом тактов через 2,0 секунды.

            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: {

          })
8 голосов
/ 21 августа 2013

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:] и т. Д .... и в методе получения вы можете преобразовать число в ваш формат как [число int] или [число двойное].

5 голосов
/ 02 августа 2016

Вот способ Swift 3 поставить работу в очередь после задержки.

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