Question Comment déclencher un bloc après un délai, comme -performSelector: withObject: afterDelay :?


Y at-il un moyen d'appeler un bloc avec un paramètre primitif après un délai, comme l'utilisation performSelector:withObject:afterDelay: mais avec un argument comme int/double/float?


691
2017-11-09 22:13


origine


Réponses:


Je pense que tu cherches dispatch_after(). Il nécessite que votre bloc n'accepte aucun paramètre, mais vous pouvez simplement laisser le bloc capturer ces variables à partir de votre portée locale.

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);
});

Plus: https://developer.apple.com/documentation/dispatch/1452876-dispatch_after


1118
2017-11-09 22:28



Vous pouvez utiliser dispatch_after appeler un bloc plus tard. Dans Xcode, commencez à taper dispatch_after et frapper Enter pour compléter automatiquement les éléments suivants:

enter image description here

Voici un exemple avec deux flotteurs comme "arguments". Vous n'avez pas besoin de compter sur un type de macro, et l'intention du code est assez claire:

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)")
}

Objectif 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);
});

463
2017-10-24 03:01



Pourquoi ne pas utiliser la bibliothèque d'extraits de code intégrée de Xcode?

enter image description here

Mise à jour pour Swift:

De nombreux votes m'ont inspiré pour mettre à jour cette réponse.

La bibliothèque d'extraits de code Xcode intégrée a dispatch_after pour seulement objective-c la langue. Les gens peuvent aussi créer leur propre Extrait de code personnalisé pour Swift.

Ecrivez ceci dans 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#>
    })

Faites glisser ce code et déposez-le dans la zone de la bibliothèque de fragments de code. enter image description here

En bas de la liste des extraits de code, il y aura une nouvelle entité nommée My Code Snippet. Modifiez ceci pour un titre. Pour suggestion que vous tapez dans le Xcode remplissez le Completion Shortcut.

Pour plus d'informations voir CreatingaCustomCodeSnippet.

Mettre à jour Swift 3

Faites glisser ce code et déposez-le dans la zone de la bibliothèque de fragments de code.

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(<#delayInSeconds#>)) {
    <#code to be executed after a specified delay#>
}

188
2018-05-23 06:19



En développant la réponse de Jaime Cham, j'ai créé une catégorie NSObject + Blocks comme ci-dessous. Je sentais que ces méthodes correspondaient mieux aux performSelector: Méthodes 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

et utilisez comme ça:

[anyObject performBlock:^{
    [anotherObject doYourThings:stuff];
} afterDelay:0.15];

56
2018-02-12 10:15



Peut-être plus simple que de passer par GCD, dans une classe quelque part (par exemple "Util"), ou une Catégorie sur Objet:

+ (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];
}

Donc, pour utiliser:

[Util runAfterDelay:2 block:^{
    NSLog(@"two seconds later!");
}];

21
2017-09-27 08:51



Pour Swift j'ai créé une fonction globale, rien de spécial, en utilisant le dispatch_after méthode. J'aime plus cela car il est lisible et facile à utiliser:

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)
}

Ce que vous pouvez utiliser comme suit:

performBlock({ () -> Void in
    // Perform actions
}, afterDelay: 0.3)

21
2018-04-08 09:30



Voici mes 2 cents = 5 méthodes;)

J'aime encapsuler ces détails et avoir AppCode me dire comment finir mes phrases.

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);
}

16
2018-02-24 22:14



PerformSelector: WithObject prend toujours un objet, donc afin de passer des arguments comme int / double / float etc ..... Vous pouvez utiliser quelque chose comme ça.

// NSNumber est un objet ..

[self performSelector:@selector(setUserAlphaNumber:)
     withObject: [NSNumber numberWithFloat: 1.0f]       
     afterDelay:1.5];



-(void) setUserAlphaNumber: (NSNumber*) number{

     [txtUsername setAlpha: [number floatValue] ];

}

De même que vous pouvez utiliser [NSNumber numberWithInt:] etc ... et dans la méthode de réception, vous pouvez convertir le nombre dans votre format en tant que [nombre entier] ou [nombre double].


8
2017-08-21 10:31