ale co jeśli chcesz przełączać się między widokami? Kod się zatrzyma, prawda?
Cing
5
@Cing zależy od tego, do czego się odnosi.
Antzi
1
Nie zapominaj, że NSTimerzachowuje swój cel, więc przy tej konfiguracji, jeśli helloWorldTimerjest to właściwość self, masz cykl utrzymania, w którym selfzachowuje helloWorldTimeri helloWorldTimerzachowuje self.
MANIAK_dobrii
@MANIAK_dobrii Czy możesz również skomentować, jak przerwać cykl przechowywania? Jeśli VC zostanie odrzucony, ale licznik czasu nie zostanie anulowany, cykl nadal działa? Więc musicie oboje anulować licznik czasu, a następnie odrzucić widok, aby przerwać cykl?
Dave G
1
W przypadku Swift 4 metoda, której chcesz uzyskać selektor, musi być uwidoczniona w Objective-C, dlatego atrybut @objc musi zostać dodany do deklaracji metody. np. `` @objc func sayHello () {} ''
Shamim Hossain
136
Jeśli celujesz w system iOS w wersji 10 lub nowszej, możesz użyć wersji opartej na blokach Timer, co upraszcza potencjalne silne cykle odwołań, np .:
weakvar timer:Timer?func startTimer(){
timer?.invalidate()// just in case you had existing `Timer`, `invalidate` it before we lose our reference to it
timer =Timer.scheduledTimer(withTimeInterval:60.0, repeats:true){[weakself]_in// do something here
}}func stopTimer(){
timer?.invalidate()}// if appropriate, make sure to stop your timer in `deinit`
deinit{
stopTimer()}
Chociaż Timerogólnie jest to najlepsze, ze względu na kompletność należy zauważyć, że można również użyć licznika czasu wysyłki, który jest przydatny do planowania liczników czasu w wątkach w tle. Dzięki zegarom wysyłkowym, ponieważ są one oparte na blokach, unika się niektórych silnych wyzwań cyklu referencyjnego ze starym wzorcem target/ , o ile używasz odwołań.selectorTimerweak
Więc:
var timer:DispatchSourceTimer?func startTimer(){let queue =DispatchQueue(label:"com.domain.app.timer")// you can also use `DispatchQueue.main`, if you want
timer =DispatchSource.makeTimerSource(queue: queue)
timer!.schedule(deadline:.now(), repeating:.seconds(60))
timer!.setEventHandler {[weakself]in// do whatever you want here
}
timer!.resume()}func stopTimer(){
timer?.cancel()
timer =nil}deinit{self.stopTimer()}
Aby uzyskać więcej informacji, zobacz The Tworzenie timera odcinek Wysłanie źródłowe przykładów w dyspozytorskie Sources sekcji Programowanie Współbieżnym Guide.
w jaki sposób w ramach tego podejścia zastosowałbyś licznik czasu wykonywania tylko raz?
Juan Boero
@JuanPabloBoero - Nie użyłbym tego podejścia do sytuacji jednorazowego pożaru. Używałbyś dispatch_after. Lub niepowtarzalny NSTimer.
Rob
@Rob Mam na ekranie etykietę licznika, która jest aktualizowana co sekundę z funkcji i używam powyższego kodu do zwiększania licznika i aktualizowania tekstu etykiety. Ale problem, z którym się zmagam, polega na tym, że moja zmienna licznika jest aktualizowana co sekundę, ale ekran nie pokazuje najnowszej wartości licznika w moim UILabel.
Nagendra Rao
Rao, powyższe jest przydatne do wykonywania pewnych czynności w wątku w tle. Ale aktualizacje interfejsu użytkownika muszą odbywać się w głównej kolejce. Więc zaplanuj to w głównym wątku lub przynajmniej wyślij aktualizacje interfejsu użytkownika z powrotem do głównego wątku.
Rob
1
To pytanie nie należy tutaj w komentarzach do tej odpowiedzi. Usuń swoje komentarze powyżej i zadaj własne pytanie. Krótko mówiąc, generalnie nie utrzymujesz aplikacji działającej w tle, a jedynie sprawiasz, że wygląda tak, jakby była. Zobacz stackoverflow.com/a/31642036/1271826 .
Rob
17
Oto aktualizacja NSTimerodpowiedzi dla języka Swift 3 (w którym NSTimerzmieniono nazwę na Timer) przy użyciu zamknięcia zamiast nazwanej funkcji:
var timer =Timer.scheduledTimer(withTimeInterval:60, repeats:true){(_)in
print("Hello world")}
Jeśli możesz pozwolić sobie na dryf w czasie, oto proste rozwiązanie wykonujące jakiś kod co minutę:
privatefunc executeRepeatedly(){// put your code here
DispatchQueue.main.asyncAfter(deadline:.now()+60.0){[weakself]inself?.executeRepeatedly()}}
Po prostu uruchom executeRepeatedly()raz i będzie wykonywane co minutę. Wykonywanie zatrzymuje się po selfzwolnieniu obiektu będącego właścicielem ( ). Możesz również użyć flagi, aby wskazać, że wykonanie musi zostać zatrzymane.
let timer :DispatchSourceTimer=DispatchSource.makeTimerSource(flags:[], queue:DispatchQueue.main)
timer.scheduleRepeating(deadline:.now(), interval:.seconds(60))
timer.setEventHandler
{NSLog("Hello World")}
timer.resume()
Jest to szczególnie przydatne, gdy chcesz wysłać wiadomość w określonej kolejce. Ponadto, jeśli planujesz używać tego do aktualizacji interfejsu użytkownika, sugeruję sprawdzenie, CADisplayLinkczy jest zsynchronizowany z częstotliwością odświeżania GPU.
Odpowiedzi:
Pamiętaj, aby zaimportować Foundation.
Swift 4:
źródło
NSTimer
zachowuje swój cel, więc przy tej konfiguracji, jeślihelloWorldTimer
jest to właściwośćself
, masz cykl utrzymania, w którymself
zachowujehelloWorldTimer
ihelloWorldTimer
zachowujeself
.Jeśli celujesz w system iOS w wersji 10 lub nowszej, możesz użyć wersji opartej na blokach
Timer
, co upraszcza potencjalne silne cykle odwołań, np .:Chociaż
Timer
ogólnie jest to najlepsze, ze względu na kompletność należy zauważyć, że można również użyć licznika czasu wysyłki, który jest przydatny do planowania liczników czasu w wątkach w tle. Dzięki zegarom wysyłkowym, ponieważ są one oparte na blokach, unika się niektórych silnych wyzwań cyklu referencyjnego ze starym wzorcemtarget
/ , o ile używasz odwołań.selector
Timer
weak
Więc:
Aby uzyskać więcej informacji, zobacz The Tworzenie timera odcinek Wysłanie źródłowe przykładów w dyspozytorskie Sources sekcji Programowanie Współbieżnym Guide.
W przypadku Swift 2 zobacz poprzednią wersję tej odpowiedzi .
źródło
dispatch_after
. Lub niepowtarzalnyNSTimer
.Oto aktualizacja
NSTimer
odpowiedzi dla języka Swift 3 (w którymNSTimer
zmieniono nazwę naTimer
) przy użyciu zamknięcia zamiast nazwanej funkcji:źródło
Jeśli możesz pozwolić sobie na dryf w czasie, oto proste rozwiązanie wykonujące jakiś kod co minutę:
Po prostu uruchom
executeRepeatedly()
raz i będzie wykonywane co minutę. Wykonywanie zatrzymuje się poself
zwolnieniu obiektu będącego właścicielem ( ). Możesz również użyć flagi, aby wskazać, że wykonanie musi zostać zatrzymane.źródło
Możesz użyć
Timer
(Swift 3)W selector () podajesz nazwę swojej funkcji
źródło
Timer
...NSTimer
został przemianowanyW swift 3.0 GCD został refaktoryzowany:
Jest to szczególnie przydatne, gdy chcesz wysłać wiadomość w określonej kolejce. Ponadto, jeśli planujesz używać tego do aktualizacji interfejsu użytkownika, sugeruję sprawdzenie,
CADisplayLink
czy jest zsynchronizowany z częstotliwością odświeżania GPU.źródło