Bevor ich die Anwendungsfälle für implizit nicht verpackte Optionen beschreiben kann, sollten Sie bereits verstehen, welche Optionen und implizit nicht verpackten Optionen in Swift enthalten sind. Wenn Sie dies nicht tun, empfehle ich Ihnen, zuerst meinen Artikel über Optionen zu lesen
Wann wird eine implizit ausgepackte Option verwendet?
Es gibt zwei Hauptgründe, warum man eine implizit unverpackte Option erstellen würde. Alle haben mit der Definition einer Variablen zu tun, auf die niemals zugegriffen werden kann, nil
da der Swift-Compiler Sie sonst immer zwingt, eine Option explizit zu entpacken.
1. Eine Konstante, die während der Initialisierung nicht definiert werden kann
Jede Mitgliedskonstante muss bis zum Abschluss der Initialisierung einen Wert haben. Manchmal kann eine Konstante während der Initialisierung nicht mit ihrem korrekten Wert initialisiert werden, es kann jedoch garantiert werden, dass sie vor dem Zugriff einen Wert hat.
Die Verwendung einer optionalen Variablen umgeht dieses Problem, da eine optionale Variable automatisch mit initialisiert wird nil
und der Wert, den sie möglicherweise enthält, weiterhin unveränderlich ist. Es kann jedoch schmerzhaft sein, eine Variable, von der Sie sicher wissen, dass sie nicht gleich Null ist, ständig auszupacken. Implizit unverpackte Optionen bieten die gleichen Vorteile wie eine Option mit dem zusätzlichen Vorteil, dass sie nicht überall explizit ausgepackt werden müssen.
Ein gutes Beispiel hierfür ist, wenn eine Mitgliedsvariable in einer UIView-Unterklasse erst initialisiert werden kann, wenn die Ansicht geladen ist:
class MyView: UIView {
@IBOutlet var button: UIButton!
var buttonOriginalWidth: CGFloat!
override func awakeFromNib() {
self.buttonOriginalWidth = self.button.frame.size.width
}
}
Hier können Sie die ursprüngliche Breite der Schaltfläche erst berechnen, wenn die Ansicht geladen wurde. Sie wissen jedoch, dass awakeFromNib
diese vor jeder anderen Methode in der Ansicht (außer der Initialisierung) aufgerufen wird. Anstatt zu erzwingen, dass der Wert in Ihrer gesamten Klasse explizit sinnlos entpackt wird, können Sie ihn als implizit entpackte Option deklarieren.
2. Wenn Ihre App nicht von einem variablen Wesen wiederhergestellt werden kann nil
Dies sollte äußerst selten sein. Wenn Ihre App jedoch nil
beim Zugriff auf eine Variable nicht weiter ausgeführt werden kann, ist es Zeitverschwendung, sie zu testen nil
. Wenn Sie eine Bedingung haben, die unbedingt erfüllt sein muss, damit Ihre App weiter ausgeführt werden kann, verwenden Sie normalerweise eine assert
. In eine implizit entpackte Option ist eine Zusicherung für Null integriert. Selbst dann ist es oft gut, das Optionale auszupacken und eine aussagekräftigere Aussage zu verwenden, wenn es Null ist.
Wann nicht verwendet werden? Implizit unverpackt Optional
1. Faul berechnete Mitgliedsvariablen
Manchmal haben Sie eine Mitgliedsvariable, die niemals Null sein sollte, die jedoch während der Initialisierung nicht auf den richtigen Wert gesetzt werden kann. Eine Lösung besteht darin, eine implizit nicht verpackte Option zu verwenden. Eine bessere Möglichkeit ist jedoch die Verwendung einer faulen Variablen:
class FileSystemItem {
}
class Directory : FileSystemItem {
lazy var contents : [FileSystemItem] = {
var loadedContents = [FileSystemItem]()
// load contents and append to loadedContents
return loadedContents
}()
}
Jetzt wird die Mitgliedsvariable contents
erst beim ersten Zugriff initialisiert. Dies gibt der Klasse die Möglichkeit, vor der Berechnung des Anfangswertes in den richtigen Zustand zu gelangen.
Hinweis: Dies scheint # 1 von oben zu widersprechen. Es ist jedoch eine wichtige Unterscheidung zu treffen. Das buttonOriginalWidth
Obige muss während viewDidLoad festgelegt werden, um zu verhindern, dass jemand die Breite der Schaltflächen ändert, bevor auf die Eigenschaft zugegriffen wird.
2. Überall sonst
Implizit nicht verpackte Optionen sollten größtenteils vermieden werden, da bei falscher Verwendung Ihre gesamte App abstürzt, wenn währenddessen auf sie zugegriffen wird nil
. Wenn Sie sich nie sicher sind, ob eine Variable Null sein kann, verwenden Sie immer standardmäßig eine normale Optionale Option. Das Auspacken einer Variablen, die niemals nil
sicher ist, tut nicht sehr weh.
if someOptional
.hasValue
ist direkt auf Optional definiert. Ich bevorzuge die Semantik vonhasValue
denen von!= nil
. Ich denke, es ist viel verständlicher für neue Programmierer, die nichtnil
in anderen Sprachen verwendet haben.hasValue
ist viel logischer alsnil
.hasValue
als wäre es aus der Beta 6 gezogen worden. Ash hat es aber zurückgesetzt ... github.com/AshFurrow/hasValueImplizit entpackte Optionen sind nützlich, um eine Eigenschaft als nicht optional darzustellen, wenn sie wirklich unter der Decke optional sein muss. Dies ist häufig erforderlich, um den Knoten zwischen zwei verwandten Objekten zu binden, die jeweils einen Verweis auf das andere benötigen. Es ist sinnvoll, wenn keine der Referenzen tatsächlich optional ist, aber eine von ihnen Null sein muss, während das Paar initialisiert wird.
Zum Beispiel:
Jede
B
Instanz sollte immer eine gültigemyBuddyA
Referenz haben, damit der Benutzer sie nicht als optional behandelt, aber sie muss optional sein, damit wir eine erstellen können,B
bevor wir eineA
Referenz haben.JEDOCH! Diese Art der gegenseitigen Bezugsanforderung ist häufig ein Hinweis auf eine enge Kopplung und ein schlechtes Design. Wenn Sie sich auf implizit entpackte Optionen verlassen, sollten Sie wahrscheinlich ein Refactoring in Betracht ziehen, um die gegenseitigen Abhängigkeiten zu beseitigen.
quelle
@IBOutlet
weak
Implizit ausgepackte Optionen sind ein pragmatischer Kompromiss, um die Arbeit in einer Hybridumgebung, die mit vorhandenen Cocoa-Frameworks und deren Konventionen zusammenarbeiten muss, angenehmer zu gestalten und gleichzeitig eine schrittweise Migration in ein sichereres Programmierparadigma zu ermöglichen - ohne Nullzeiger -, das vom Swift-Compiler erzwungen wird.
Das schnelle Buch im Kapitel " Grundlagen" im Abschnitt " Implizit unverpackte Optionen" lautet:
Dies ist auf Anwendungsfälle zurückzuführen, in denen die Nicht-
nil
Nichtigkeit von Eigenschaften über eine Verwendungskonvention festgelegt wird und vom Compiler während der Klasseninitialisierung nicht erzwungen werden kann. Zum Beispiel dieUIViewController
Eigenschaften, die über NIBs oder Storyboards initialisiert werden, wobei die Initialisierung in separate Phasen unterteilt ist. DanachviewDidLoad()
können Sie jedoch davon ausgehen, dass Eigenschaften im Allgemeinen vorhanden sind. Andernfalls mussten Sie, um den Compiler zufrieden zu stellen, das erzwungene Entpacken , das optionale Binden oder das optionale Verketten verwenden , um den Hauptzweck des Codes zu verschleiern.Der obige Teil aus dem Swift-Buch bezieht sich auch auf das Kapitel Automatische Referenzzählung :
Dies ist darauf zurückzuführen, dass es sich nicht um eine Sprache handelt, in der Müll gesammelt wird. Daher liegt es an Ihnen als Programmierer, die Aufbewahrungszyklen zu unterbrechen, und implizit ausgepackte Optionen sind ein Werkzeug, um diese Eigenart zu verbergen.
Dies umfasst die Frage "Wann sollten implizit entpackte Optionen in Ihrem Code verwendet werden?" Frage. Als Anwendungsentwickler begegnen Sie ihnen hauptsächlich in Methodensignaturen von in Objective-C geschriebenen Bibliotheken, die keine optionalen Typen ausdrücken können.
Aus der Verwendung von Swift mit Kakao und Objective-C, Abschnitt Arbeiten mit Null :
... und dahinter lag
quelle
Einzeilige (oder mehrzeilige) einfache Beispiele decken das Verhalten von Optionen nicht sehr gut ab - ja, wenn Sie eine Variable deklarieren und ihr sofort einen Wert geben, macht eine Option keinen Sinn.
Der beste Fall, den ich bisher gesehen habe, ist das Setup, das nach der Objektinitialisierung erfolgt, gefolgt von einer Verwendung, die "garantiert" diesem Setup folgt, z. B. in einem View Controller:
Wir wissen
printSize
, dass der Aufruf nach dem Laden der Ansicht erfolgt - es handelt sich um eine Aktionsmethode, die mit einem Steuerelement in dieser Ansicht verbunden ist, und wir haben darauf geachtet, sie nicht anders aufzurufen. So können wir uns einige optionale Überprüfungen / Bindungen mit dem sparen!
. Swift kann diese Garantie nicht erkennen (zumindest bis Apple das Problem mit dem Anhalten gelöst hat), sodass Sie dem Compiler mitteilen, dass sie vorhanden ist.Dies bricht jedoch die Typensicherheit bis zu einem gewissen Grad. An jedem Ort, an dem Sie eine implizit ausgepackte Option haben, kann Ihre App abstürzen, wenn Ihre "Garantie" nicht immer gilt. Daher sollten Sie diese Funktion sparsam verwenden. Außerdem
!
klingt es so, als würdest du schreien, wenn du die ganze Zeit benutzt, und das gefällt niemandem.quelle
CGSizeZero
sie im realen Gebrauch ein guter Sentinel-Wert sein kann. Aber was ist, wenn Sie eine Größe von der Feder geladen haben, die tatsächlich Null sein könnte?CGSizeZero
Wenn Sie dann als Sentinel verwenden, können Sie nicht zwischen einem nicht festgelegten und einem auf Null gesetzten Wert unterscheiden. Darüber hinaus gilt dies ebenso gut für andere Typen, die von nib (oder irgendwo anders danachinit
) geladen wurden : Zeichenfolgen, Verweise auf Unteransichten usw.let foo? = 42
, eherlet foo! = 42
). Das spricht das nicht an. (Dies kann eine relevante Antwort über Optionals sein, wohlgemerkt, aber nicht über implizit ausgepackte Optionals, die ein anderes / verwandtes Tier sind.)Apple gibt ein gutes Beispiel in der Programmiersprache Swift -> Automatische Referenzzählung -> Auflösen starker Referenzzyklen zwischen Klasseninstanzen -> Nicht besessene Referenzen und implizit nicht verpackte optionale Eigenschaften
quelle
Die Gründe für implizite Optionen lassen sich leichter erklären, indem zunächst die Gründe für das erzwungene Auspacken betrachtet werden.
Erzwungenes Auspacken eines optionalen (impliziten oder nicht impliziten) mit dem! Operator bedeutet, dass Sie sicher sind, dass Ihr Code keine Fehler enthält und das optionale Code bereits einen Wert hat, in dem es entpackt wird. Ohne das ! Operator, würden Sie wahrscheinlich nur mit einer optionalen Bindung behaupten:
das ist nicht so schön wie
Mit impliziten Optionen können Sie jetzt ausdrücken, dass in allen möglichen Flows ein optionales Element vorhanden ist, von dem Sie erwarten , dass es beim Auspacken immer einen Wert hat. Es geht also noch einen Schritt weiter, um Ihnen zu helfen - indem Sie die Anforderungen an das Schreiben des! jedes Mal auspacken und sicherstellen, dass die Laufzeit weiterhin fehlerhaft ist, falls Ihre Annahmen über den Ablauf falsch sind.
quelle
init
(die Sie möglicherweise nicht einmal implementieren), aber sie ' wird garantiert nachawakeFromNib
/ eingestelltviewDidLoad
.Wenn Sie sicher wissen, ein Wert , der Rückkehr von einem optionalen statt
nil
, Implizit Unwrapped Optionals verwenden , um direkt die Werte von optionals und nicht optionals fangen nicht.Das ist also der Unterschied zwischen der Verwendung von
let someString : String!
undlet someString : String
quelle
Ich denke, es
Optional
ist ein schlechter Name für dieses Konstrukt, das viele Anfänger verwirrt.Andere Sprachen (z. B. Kotlin und C #) verwenden den Begriff
Nullable
, und dies erleichtert das Verständnis erheblich.Nullable
bedeutet, dass Sie einer Variablen dieses Typs einen Nullwert zuweisen können. Wenn dies derNullable<SomeClassType>
Fall ist , können Sie ihm Nullen zuweisen. Wenn dies nur der Fall istSomeClassType
, können Sie dies nicht. So funktioniert Swift.Warum sie benutzen? Manchmal muss man Nullen haben, deshalb. Wenn Sie beispielsweise wissen, dass Sie ein Feld in einer Klasse haben möchten, es aber beim Erstellen einer Instanz dieser Klasse nichts zuweisen können, werden Sie dies später tun. Ich werde keine Beispiele nennen, weil die Leute sie hier bereits zur Verfügung gestellt haben. Ich schreibe das nur auf, um meine 2 Cent zu geben.
Übrigens, ich schlage vor, Sie schauen sich an, wie dies in anderen Sprachen wie Kotlin und C # funktioniert.
Hier ist ein Link, der diese Funktion in Kotlin erklärt: https://kotlinlang.org/docs/reference/null-safety.html
Andere Sprachen wie Java und Scala haben zwar
Optional
s, funktionieren jedoch anders alsOptional
s in Swift, da die Typen von Java und Scala standardmäßig alle nullwertfähig sind.Alles in allem denke ich, dass diese Funktion
Nullable
in Swift benannt worden sein sollte und nichtOptional
...quelle
Implicitly Unwrapped Optional
ist ein syntaktischer ZuckerOptional
, der einen Programmierer nicht zwingt, eine Variable zu entpacken. Es kann für eine Variable verwendet werden, die während nicht initialisiert werden kanntwo-phase initialization process
und nicht Null impliziert . Diese Variable verhält sich wie Nicht-Null , ist jedoch eine optionale Variable. Ein gutes Beispiel ist - Interface Builder's OutletsOptional
in der Regel sind vorzuziehenquelle