web-dev-qa-db-ja.com

performSelector:withObject:afterDelayの代わりにブロック:

将来、いくつかのコードを数マイクロ秒実行したいことがよくあります。今、私はこれを次のように解決します:

- (void)someMethod
{
    // some code
}

この:

[self performSelector:@selector(someMethod) withObject:nil afterDelay:0.1];

動作しますが、毎回新しいメソッドを作成する必要があります。これの代わりにブロックを使用することは可能ですか?基本的に私は次のような方法を探しています:

[self performBlock:^{
    // some code
} afterDelay:0.1];

それは私にとって本当に役立つでしょう。

87
Rits

それを行うための組み込みの方法はありませんが、カテゴリを介して追加することは悪くありません:

@implementation NSObject (PerformBlockAfterDelay)

- (void)performBlock:(void (^)(void))block 
          afterDelay:(NSTimeInterval)delay 
{
    block = [[block copy] autorelease];
    [self performSelector:@selector(fireBlockAfterDelay:) 
               withObject:block 
               afterDelay:delay];
}

- (void)fireBlockAfterDelay:(void (^)(void))block {
    block();
}

@end

基本的な実装は Mike Ash によるものです。

106
John Calsbeek

GCDに基づいた、私が使用している簡単な手法を次に示します。

void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
      dispatch_get_current_queue(), block);
}

私はGCDの専門家ではありません。このソリューションに関するコメントに興味があります。

41
Nick Moore

別の方法(多くの理由でおそらくこれを行う最悪の方法)は次のとおりです。

[UIView animateWithDuration:0.0 delay:5.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
} completion:^(BOOL finished) {
    //do stuff here
}];
22
ninjaneer

より長い遅延が特に必要な場合、上記のソリューションは問題なく機能します。 @nickのアプローチを使用して大成功を収めました。

ただし、メインループの次の反復中にブロックを実行するだけの場合は、次のようにすれば、さらにブロックを削減できます。

[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];

これは、performSelectorを使用するのと似ています:afterDelayが0.0fの場合

16
Greg Combs

私はこのような同様のコードを使用しました:

double delayInSeconds = 0.2f;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
      //whatever you wanted to do here...  
    });
11
Despotovic

この状況を処理する、すてきな完全なカテゴリがここにあります。

https://Gist.github.com/95512

1
Duane Fields