Ja, NSTimer
wird eine starke Bezugnahme auf die target
beibehalten, die (besonders in Wiederholungstimern) starke Referenzzyklen (a.k.a. Retain-Zyklen) verursachen kann. In Ihrem Beispiel wird der Timer jedoch nicht wiederholt und nur um 0,5 verzögert. Im schlimmsten Fall haben Sie also einen starken Referenzzyklus, der sich automatisch in 0,5 Sekunden auflöst.
Aber ein typisches Beispiel eines ungelösten starken Referenzzyklus würde ein UIViewController
mit einer NSTimer
Eigenschaft zu haben, die wiederholt, sondern weil die NSTimer
einen starken Hinweis auf die UIViewController
hat, wird der Controller am Ende zurückgehalten wird.
Also, wenn Sie die NSTimer
als Instanzvariable behalten, dann sollten Sie invalidate
es, um den starken Referenzzyklus zu lösen. Wenn Sie nur scheduledTimerWithTimeInterval
aufrufen, aber nicht in einer Instanzvariable speichern (wie Sie aus Ihrem Beispiel entnehmen können), wird Ihr starker Referenzzyklus aufgelöst, wenn die NSTimer
abgeschlossen ist.
Und, nebenbei bemerkt, wenn Sie mit dem Wiederholen NSTimers
es zu tun, versuchen Sie nicht zu invalidate
sie in dealloc
des Eigentümers der NSTimer
weil die dealloc
wird aufgerufen, offensichtlich nicht, bis der starke Zyklus Referenz behoben ist. Im Fall einer UIViewController
zum Beispiel, könnten Sie es in viewDidDisappear
tun.
Übrigens, die Advanced Memory Management Programming Guide erklärt, was starke Referenzzyklen sind. Dies ist eindeutig in einem Abschnitt, in dem sie die korrekte Verwendung von schwachen Referenzen beschreiben, was hier nicht anwendbar ist (weil Sie keine Kontrolle über die Tatsache haben, dass NSTimer
starke Verweise auf das Ziel verwendet), aber es erklärt die Konzepte von starken Referenzzyklen schön.
Wenn Sie Ihr NSTimer
nicht möchten, zu self
einen starken Bezug zu halten, in macOS 10.12 und iOS 10 oder höher können Sie den Block Wiedergabe verwenden und verwenden Sie dann die weakSelf
Muster:
typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:0.5 repeats:false block:^(NSTimer * _Nonnull timer) {
[weakSelf showButtons];
}];
Übrigens bemerke ich, dass Sie showButtons
anrufen. Wenn Sie versuchen, auf Ihrer Ansicht zeigen nur einige Steuerelemente, können Sie die Verwendung des NSTimer
zusammen beseitigen und so etwas wie:
self.button1.alpha = 0.0;
self.button2.alpha = 0.0;
[UIView animateWithDuration:0.25
delay:0.5
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
animations:^{
self.button1.alpha = 1.0;
self.button2.alpha = 1.0;
}
completion:nil];
Diese leiden nicht die behalten Fragen der NSTimer
Objekte, und beide durchführt die Verzögerung sowie die anmutige Darstellung der Schaltfläche (n) in einer Aussage.Wenn Sie in Ihrer showButtons
-Methode eine zusätzliche Verarbeitung durchführen, können Sie diese in den Block completion
einfügen.
Große Antwort, aber vielleicht habe ich nicht die Tatsache klar gemacht, dass ich es nicht wirklich in der .h-Datei mit NSTimer * timer deklariere, ich füge einfach diesen Code in die .m-Datei, so dass ich nicht ungültig oder null es . In diesem Fall ist es immer noch in Ordnung, wenn ich meinen Timer verwende, oder ist es besser, den Code zu verwenden, den Sie mir zur Verfügung gestellt haben? – Alessandro
@Alessandro Ich vermutete, dass du keinen Timer für den Timer bereithältst. Aber wenn Sie 'viewWillDisappear' invalidieren wollen, müssen Sie dies natürlich tun. (Nebenbei, Sie müssen keine privaten Ivars in Ihre .h; private Class Extension legen, ist besser.) Und ein paar Mal haben Sie erwähnt, wie man einen 'NSTimer' auf' nil' setzt. Bitte beachten Sie, dass dies keinen starken Referenzzyklus löst. Der Timer muss entweder abgeschlossen werden (und nicht wiederholt werden) oder Sie müssen (mit Ihrem neuen ivar) ungültig machen. – Rob