Odpowiedzi:
Po pierwsze chciałbym zwrócić uwagę na dokumentację Cocoa / CF (która zawsze jest świetnym pierwszym punktem kontaktowym). Dokumenty Apple mają sekcję u góry każdego artykułu zatytułowanego „Przewodniki towarzyszące”, w której znajdują się przewodniki dotyczące dokumentowanego tematu (jeśli takie istnieją). Na przykład, z NSTimer
, dokumentacja zawiera dwie przewodników towarzyszących:
W tej sytuacji najbardziej przydatne będzie artykuł dotyczący programowania czasowego, podczas gdy tematy wątków są powiązane, ale nie najbardziej bezpośrednio związane z dokumentowaną klasą. Jeśli spojrzysz na artykuł Tematy programowania czasowego, jest on podzielony na dwie części:
W przypadku artykułów, które przyjmują ten format, często znajduje się przegląd klasy i jej zastosowania, a następnie przykładowy kod, jak go używać, w tym przypadku w sekcji „Korzystanie z timerów”. Istnieją sekcje na temat „Tworzenie i planowanie timera”, „Zatrzymywanie timera” i „Zarządzanie pamięcią”. Z artykułu, tworzenie zaplanowanego, niepowtarzalnego timera można zrobić w następujący sposób:
[NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(targetMethod:)
userInfo:nil
repeats:NO];
Spowoduje to utworzenie licznika, który jest uruchamiany po 2,0 sekundach i wywołuje targetMethod:
się self
z jednym argumentem, który jest wskaźnikiem do NSTimer
instancji.
Jeśli chcesz przyjrzeć się bardziej szczegółowo metodzie, możesz odwołać się do dokumentacji, aby uzyskać więcej informacji, ale kod zawiera również wyjaśnienia.
Jeśli chcesz zatrzymać licznik czasu, który się powtarza (lub zatrzymać niepowtarzalny licznik czasu przed jego uruchomieniem), musisz zachować wskaźnik do utworzonej NSTimer
instancji; często musi to być zmienna instancji, aby można było odwoływać się do niej w innej metodzie. Następnie można nazwać invalidate
na NSTimer
przykład:
[myTimer invalidate];
myTimer = nil;
Dobrą praktyką jest także nil
wykluczanie zmiennej instancji (na przykład, jeśli twoja metoda unieważniająca licznik czasu jest wywoływana więcej niż jeden raz, a zmienna instancji nie została ustawiona, nil
a NSTimer
instancja została cofnięta, spowoduje to wyjątek).
Zwróć też uwagę na punkt dotyczący zarządzania pamięcią na dole tego artykułu:
Ponieważ pętla uruchamiania utrzymuje stoper, z punktu widzenia zarządzania pamięcią zazwyczaj nie ma potrzeby utrzymywania odniesienia do timera po jego zaplanowaniu . Ponieważ licznik czasu jest przekazywany jako argument, gdy określasz jego metodę jako selektor, możesz unieważnić powtarzający się licznik czasu, jeśli jest to właściwe w ramach tej metody . Jednak w wielu sytuacjach, chcesz także opcję unieważnienia timera - być może nawet przed jego uruchomieniem. W takim przypadku musisz zachować odniesienie do timera, abyś mógł w razie potrzeby wysłać mu unieważnioną wiadomość. Jeśli utworzysz nieplanowany licznik czasu (patrz „Nieplanowane liczniki czasu”), musisz zachować silne odniesienie do licznika czasu (w środowisku zliczanym referencjami, zachowujesz go), aby nie został zwolniony przed użyciem.
YES
do repeats:
kiedy dzwonisz scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
. Jeśli to zrobisz, pamiętaj, aby zachować odwołanie do NSTimer
instancji (jest zwracane przez metodę) i postępuj zgodnie z punktem Zarządzania pamięcią, jak opisano powyżej.
target
i selector
. Na przykład, jeśli twoim celem jest, self
a selektorem jest timerMethod:
, metoda wywoływana podczas odpalania timera jest timerMethod:
zdefiniowana na self
. Następnie możesz wstawić dowolny kod do tej metody, a metoda będzie wywoływana przy każdym uruchomieniu timera. Zauważ, że metoda wywoływana podczas uruchamiania timera (którą podajesz jako selector:
) może przyjąć tylko jeden argument (który po wywołaniu jest wskaźnikiem do NSTimer
instancji).
self
”
istnieje kilka sposobów korzystania z timera:
1) Zaplanowany timer i użycie selektora
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:@selector(onTick:)
userInfo: nil repeats:NO];
Na marginesie, zamiast używać timera, który się nie powtarza i wywołuje selektor po określonym czasie, możesz użyć prostej instrukcji takiej jak ta:
[self performSelector:@selector(onTick:) withObject:nil afterDelay:2.0];
będzie to miało taki sam efekt jak powyższy przykładowy kod; ale jeśli chcesz wywoływać selektor co n-ty raz, używasz timera z powtórzeniami: TAK;
2) samowyzwalacz czasowy
NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
interval: 1
target: self
selector:@selector(onTick:)
userInfo:nil repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
3) nieplanowany zegar i użycie wywołania
NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(onTick:)];
NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
invocation:inv
repeats:YES];
a następnie ręcznie uruchamiasz stoper, gdy potrzebujesz:
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];
Uwaga: metoda onTick: wygląda następująco:
-(void)onTick:(NSTimer *)timer {
//do smth
}
Coś takiego:
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: @selector(handleTimer:)
userInfo: nil
repeats: YES];
#import "MyViewController.h"
@interface MyViewController ()
@property (strong, nonatomic) NSTimer *timer;
@end
@implementation MyViewController
double timerInterval = 1.0f;
- (NSTimer *) timer {
if (!_timer) {
_timer = [NSTimer timerWithTimeInterval:timerInterval target:self selector:@selector(onTick:) userInfo:nil repeats:YES];
}
return _timer;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
-(void)onTick:(NSTimer*)timer
{
NSLog(@"Tick...");
}
@end
MyViewController
nigdy nie zostaje zwolniony.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(timerCalled) userInfo:nil repeats:NO];
-(void)timerCalled
{
NSLog(@"Timer Called");
// Your Code
}
W odpowiedziach brakuje określonego timera dnia tutaj jest na następną godzinę:
NSCalendarUnit allUnits = NSCalendarUnitYear | NSCalendarUnitMonth |
NSCalendarUnitDay | NSCalendarUnitHour |
NSCalendarUnitMinute | NSCalendarUnitSecond;
NSCalendar *calendar = [[ NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents = [calendar components: allUnits
fromDate: [ NSDate date ] ];
[ weekdayComponents setHour: weekdayComponents.hour + 1 ];
[ weekdayComponents setMinute: 0 ];
[ weekdayComponents setSecond: 0 ];
NSDate *nextTime = [ calendar dateFromComponents: weekdayComponents ];
refreshTimer = [[ NSTimer alloc ] initWithFireDate: nextTime
interval: 0.0
target: self
selector: @selector( doRefresh )
userInfo: nil repeats: NO ];
[[NSRunLoop currentRunLoop] addTimer: refreshTimer forMode: NSDefaultRunLoopMode];
Oczywiście zamień „doRefresh” na pożądaną przez klasę metodę
spróbuj raz utworzyć obiekt kalendarza i uczyń allUnits statycznym dla zwiększenia wydajności.
dodanie komponentu godzinnego działa dobrze, nie ma potrzeby testu północy ( link )