2013-02-17 13 views
38

Chcę być w stanie zaplanować trzy małe zdarzenia w przyszłości bez konieczności pisania funkcji dla każdego. Jak mogę to zrobić, używając NSTimer? Rozumiem, że bloki ułatwiają anonimowe funkcje, ale czy można je używać w ramach NSTimer, a jeśli tak, to w jaki sposób?NSTimer z anonimową funkcją/blokiem?

[NSTimer scheduledTimerWithTimeInterval:gameInterval 
     target:self selector:@selector(/* I simply want to update a label here */) 
     userInfo:nil repeats:NO]; 
+3

Dlaczego nie używacie 'dispatch_after()'? Jest to funkcja GCD i przyjmuje jako parametr blok. –

+0

Nigdy o nim nie słyszałem ... Jak tego użyć?Dopóki mogę powiedzieć "poczekaj X sekund a następnie rób to" Jestem szczęśliwy! – Chris

+1

co z metodą '-performSelector: withObject: afterDelay:'? – holex

Odpowiedz

22

Rzeczywiście można nazwać:

NSTimer.scheduledTimerWithTimeInterval(ti: NSTimeInterval, 
 
        target: AnyObject, 
 
        selector: #Selector, 
 
        userInfo: AnyObject?, 
 
        repeats: Bool)

Używaj go tak:

NSTimer.scheduledTimerWithTimeInterval(1, 
 
        target: NSBlockOperation(block: {...}), 
 
        selector: #selector(NSOperation.main), 
 
        userInfo: nil, 
 
        repeats: true)

+0

To fantastyczne. Dzięki. –

+0

Szybki i prosty. Działa świetnie. Dzięki! – Vitalii

+0

Powinna to być wybrana odpowiedź, ponieważ pozwala na unieważnienie licznika czasu, którego nie akceptuje zaakceptowana odpowiedź. –

56

Można skorzystać z dispatch_after jeśli chcesz osiągnąć coś podobnego do NSTimer i wykonanie bloku.

Oto przykładowy kod dla tego samego:

int64_t delayInSeconds = gameInterval; // Your Game Interval as mentioned above by you 

    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 

    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 

     // Update your label here. 

    }); 

Nadzieja to pomaga.

+9

Uwaga! Użyłeś int64_t dla swojego opóźnienia w sekundach, więc to będzie działać tylko przez całe liczby sekund! gameInterval, zgaduję, jest mniej niż 1 sekunda, więc nie zrobi tego, czego chcesz. (Szablon Xcode jest dość zwodniczy.) –

+1

Jesse ma rację. Zauważ, że rzeczywisty parametr akceptuje wartość mierzoną w * nanosekundach *, a więc stała 'NSEC_PER_SEC'. Możesz więc określić ułamki sekundy, ale musisz być ostrożny z typami liczbowymi. Coś jak '(int64_t) (gameInterval * (podwójne) NSEC_PER_SEC)' gdzie 'gameInterval' jest' podwójnym' powinno działać. – devios1

+1

Post pyta, jak to zrobić z NSTimer. Nie mogę unieważnić za pomocą dispatch_after. – circuitry

7

wersja Objective-C odpowiedzi @Peter Peng:

_actionDelayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[NSBlockOperation blockOperationWithBlock:^{ 
    NSLog(@"Well this is useless."); 
}] selector:@selector(main) userInfo:nil repeats:YES]; 
9

A block based timer API exists in Cocoa (jak iOS 10+/MacOS 10.12+) - oto jak można go używać w Swift 3:

Timer(timeInterval: gameInterval, repeats: false) { _ in 
    print("herp derp") 
} 

... lub w Objective-C:

[NSTimer scheduledTimerWithTimeInterval:gameInterval repeats:NO block:^(NSTimer *timer) { 
    NSLog(@"herp derp"); 
}]; 

Jeśli potrzebujesz docelowych wersji systemu starszych niż iOS10, macOS 12, tvOS 10, watchOS 3, powinieneś użyć jednego z innych rozwiązań.

+1

Byłem zachwycony odkryciem tego dodatku ostatnio. Biorąc pod uwagę, że mamy bloki od iOS 4, jest to trochę zaskakujące, że Apple zabrał do czasu aż iOS 10 rzuci blokowy interfejs API dla NSTimer! –

+1

Co zaskakujące, to nie działa dla mnie, przynajmniej nie w Objective-C. Blok po prostu nigdy nie zostanie wywołany. Nie ma problemu z przekroczeniem limitu czasu, ponieważ standardowa inicjalizacja NSTimer działa z tym samym limitem czasu. Nie ma problemu z utrzymaniem zmiennej NSTimer, ponieważ nie działa, nawet jeśli ją mocno trzymam. – Gobe

+0

Zapewniam, że działa API Cocoa. Prawdopodobnie wywołujesz go poza głównym wątkiem (lub innym wątkiem, który ma odpowiednio skonfigurowaną pętlę uruchamiania). – mz2

0

Uwielbiam ten hack @ Peter-Pang !! BlockOperation jest tworzony w locie, własnoręcznie przez Timer, który sam jest przez kolejkę, i wywołanie głównego selektora na bloku, aby go uruchomić .... nice !!!

Aktualizacja dla Swift 3

Timer.scheduledTimer(timeInterval: 1, target: BlockOperation { // ... }, selector: #selector(Operation.main), userInfo: nil, repeats: false)