leicht gemacht: mit NSDate die Zeit kontrollieren

Hallo Zusammen,

es gibt viele Spiele und Anwendungen die einen Bezug zur Zeit benötigen. Dies kann zum Beispiel ein Timer sein der runter läuft, bis ein Gebäude wieder gebaut werden kann. Oder es wird gezählt wie lange der Spieler in einem Level am Leben bleibt. Manchmal soll auch zu einer bestimmten Zeit, also jeden Tag im 18Uhr, etwas in der App passieren. Für alle diese Anwendungsfälle werde ich in diesem Artikel Lösungsvarianten zeigen.

Bevor wir jedoch richtig einsteigen, möchte ich jedem empfehlen ARC zu aktivieren. Ein Objekt der NSDate Klasse wird bei manueller Referenzzählung als autorelease Objekt erzeugt (wenn der Convenience Allocator [NSDate date] benutzt wird). Wollen wir das Objekt auch nach dem Benutzen in einer speziellen Methode weiterverwenden, müssen wir es durch retain und release verwalten. Mit ARC wird uns dieser Schritt abgenommen.
*UPDATE* chartus hat hierzu in den Kommentare noch eine tolle Ergänzung gemacht. Vielen Dank dafür.

die aktuelle Zeit nehmen

NSDate ist die Klasse mit der man Datumsaufgaben lösen kann. Über die Methode date erhällt man das aktuelle Datum inklusive Zeitstempel. Dies kann man sogar als String im Log ausgeben. 2013-04-09 23:18:23 +0100

   NSDate *now = [NSDate date];
   NSLog(@"es ist gerade: %@", now);

 

einen Zeitstempel verändern

Zu einem bestehenden Zeitstempel können wir eine Zeitspanne hinzufügen. In dem unten stehenden Beispiel fügen wir der aktuellen Zeit 360 Sekunden zu. Selbstverständlich kann man auch Zeit durch eine einen negativen Interval abziehen. Auf diese Weise kann ein Cooldown Zeitpunkt definiert werden. Zum aktuellen Zeitpunkt wird beispielsweise eine Aktion ausgelöst und sie soll erst in 6 Minuten wieder verfügbar sein. Wir erstellen daher eine neue NSDate Instanz coolDown und fügen 6 Minuten hinzu. Anschließend könne wir prüfen ob der coolDown Zeitstempel bereits vergangen ist, um festzustellen, ob die Aktion bereits wieder verfügbar ist.

NSDate *coolDown = [[NSDate date] dateByAddingTimeInterval:360];
NSLog(@"in 6 Minuten ist es : %@", now);

 

Zeitstempel vergleichen

Zeitstempel können nur mit compare verglichen werden. Mit == würde man nur die pointer der Variabeln vergleichen und erhält immer ein FALSE. Möchten wir nun prüfen ob der coolDown bereits abgelaufen ist, muss coolDown mit der aktuellen Zeit vergleichen werden:

NSDate *now = [NSDate date];
if ([now compare:coolDown] == NSOrderedDescending) {
      NSLog(@"coolDown Zeistempel ist älter als die aktuelle Zeit");
} else {
      NSlog(@"die aktuelle Zeit ist älter / coolDown noch in der Zukunft");
}

Zeitspannen ermitteln

Eventuell soll der Cooldown aus dem vorherigem Beispiel in der App angezeigt werden. Zu diesem Zweck müssen wir die restliche Zeitspannen ermittlen und sie z.B. in einem Label dastellen (ich nehme ein Label von cocos2d).

-(void) init{
      label = [CCLabelTTF labelWithString:[NSString stringWithFormat:@" " fontName:@"Zapfino" fontSize:16 dimensions:CGSizeMake(200, 60) hAlignment:UITextAlignmentCenter];
      label.position = ccp(240,180);
      label.color = ccc3(0,0,0);
      [self addChild:label];

      [self schedule:@selector(update)];

}
-(void)update{
      NSDateComponents *components = [[NSCalendar currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSDayCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit
                                                                       fromDate:[NSDate date]
                                                                         toDate:coolDown
                                                                        options:0];

      label.string = [NSString stringWithFormat:@"%i:%i:%i",components.hour,components.minute,components.second];
}

In der Init wird zunächst ein label definiert und hinzugefügt – hier als globale Variable. Die Update Methode muss fortlaufend aufgerufen werden – zum Beispiel mit [self schedule:@selector(update)] oder einem NSTimer. In der update Methode wird bei jedem Durchlauf ein NSDateComponents Object erzeugt. NSDateComponents zerlegt die Zeitspanne zwischen zwei NSDate Objekten  in seine einzelnen Bestandteile und macht sie so zugänglich. Anschließend wird der string des Labels aktualisiert. Wird die App nun gestartet zählt die Zeit auf dem Label runter.

Die Zeit manipulieren

Desweiteren haben wir die Möglichkeit durch NSDateComponents die Zeitstempel zu verändern. Anschließend kann aus dem manipulierten NSDateComponenents wieder ein NSDate Objekt erzeugt werden, mit dem wir weiterarbeiten.

NSDateComponents *components = [[NSCalendar currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSDayCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit
                                                                       fromDate:[NSDate date]
                                                                         toDate:coolDown
                                                                        options:0];
[components setHour:10];

NSDate *heuteUm10Uhr = [[NSCalendar currentCalendar] dateFromComponents:components];

Das sollte für die wichtigsten Aufgaben genügen. Falls ihr noch Fragen oder Probleme mit der NSDate habt, dann schreibt doch in einen Kommentar.

Bis zum nächsten mal.

2 thoughts on “leicht gemacht: mit NSDate die Zeit kontrollieren

  • ok – tut mir echt leid das ich da so drauf rumreite…

    aber! das was nun da steht ist zwar besser Formuliert aber immer noch Falsch…
    bei MRC entscheidest du als Programmierer ob ein ein Objekt welches du erzeugst autoreleased ist oder nicht.

    erzeugst du es mit [NSDate alloc] init]; ist es implizit retained und gleich gar nicht autoreleased. Wenn du es nicht korrekt irgendwann released hast du ein Memoryleak – kurz verschwendest Speicher.

    erzeugst du es dagegen mittels CA also in der Form [NSDate date]; ist es autoreleased – möchtest du es über Runzyklen und Methodenreturns verwenden mußt du es retainen – entweder direkt oder implizit (zb durch das Hinzufügen zu einem Array oder einem ordentlichen Setter) tust du das nicht, hast du einen „dangeling“ Pointer und irgendwann einen Crash beim Zugriff.

    Beim MRC entscheidest du allein über die Eigentümerschaft des Objekts.
    Und damit auch über Referenzbindung von Variablen.

    Unter ARC kannst du nur über Attribute wie strong und weak Einfluß auf die Bindungstärke der Referenzen nehmen.
    Da ist Notwendig um zb Zyklische Abhängigkeiten zu verhindern. Was nebenbei eine der größten Fehlerquellen bei der ARC Benutzung ist.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.