Как вы запускаете блок после задержки, например -performSelector: withObject: afterDelay :?

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

вопрос задан 9.11.2010
Egil
3591 репутация

17 ответов


  • 1125 рейтинг

    Я думаю, что вы ищете 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: // разработчик. яблоко. ru / document / dispatch / 1452876-dispatch_after

    ответ дан Ryan, с репутацией 15456, 9.11.2010
  • 469 рейтинг

    Вы можете использовать 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);
    });
    
    ответ дан Steven Hepting, с репутацией 9981, 24.10.2011
  • 188 рейтинг

    Как насчет использования встроенной библиотеки фрагментов кода 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#>
    }
    
    ответ дан Warif Akhand Rishi, с репутацией 17583, 23.05.2014
  • 56 рейтинг

    Расширяя ответ Хайме Чама, я создал категорию NSObject + Blocks, как показано ниже. Я чувствовал, что эти методы лучше соответствуют существующим методам NSObject performSelector:

    NSObject + Blocks. ч

    #import 
    
    @interface NSObject (Blocks)
    
    - (void)performBlock:(void (^)())block afterDelay:(NSTimeInterval)delay;
    
    @end
    

    NSObject + Blocks. м

    #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];
    
    ответ дан Oliver Pearmain, с репутацией 10726, 12.02.2013
  • 21 рейтинг

    Возможно, проще, чем пройти через 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!");
    }];
    
    ответ дан Jaime Cham, с репутацией 901, 27.09.2011
  • 21 рейтинг

    Для 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)
    
    ответ дан Antoine, с репутацией 15206, 8.04.2015
  • 16 рейтинг

    Вот мои 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);
    }
    
    ответ дан Dan Rosenstark, с репутацией 41026, 24.02.2014
  • 8 рейтинг

    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] или [число двойное].

    ответ дан Augustine, с репутацией 1524, 21.08.2013
  • 4 рейтинг

    Есть хороший пример в структуре BlocksKit.

    BlocksKit

    (и класс)

    BBlocksKit. м

    ответ дан psy, с репутацией 2496, 14.09.2012
  • 1 рейтинг

    Можно либо обернуть аргумент в своем собственном классе, либо обернуть вызов метода в метод, который не нужно передавать в примитивном типе. Затем вызовите этот метод после вашей задержки, и в пределах этого метода выполните селектор, который вы хотите выполнить.

    ответ дан GendoIkari, с репутацией 8385, 9.11.2010