Swift Language
Speicherverwaltung
Suche…
Einführung
Unmanaged
] [1] verwendet werden. [1]: https://developer.apple.com/reference/swift/unmanaged
Bemerkungen
Wann das schwache Schlüsselwort verwendet wird:
Dasweak
Schlüsselwort sollte verwendet werden, wenn ein Objekt, auf das verwiesen wird, während der Lebensdauer des Objekts freigegeben werden kann, das die Referenz enthält. Wann wird das nicht besetzte Schlüsselwort verwendet:
Dasunowned
-keyword sollte verwendet werden, wenn nicht erwartet wird, dass ein Objekt, auf das verwiesen wird, während der Lebensdauer des Objekts freigegeben wird, das die Referenz enthält. Fallstricke
Ein häufiger Fehler ist das Vergessen, Verweise auf Objekte zu erstellen, die nach dem Ende einer Funktion weiterleben müssen, z. B. Positionsmanager, Bewegungsmanager usw.Beispiel:
class A : CLLocationManagerDelegate
{
init()
{
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Dieses Beispiel funktioniert nicht ordnungsgemäß, da der Standortmanager nach der Rückkehr des Initialisierers freigegeben wird. Die richtige Lösung ist das Erstellen einer starken Referenz als Instanzvariable:
class A : CLLocationManagerDelegate
{
let locationManager:CLLocationManager
init()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Referenzzyklen und schwache Referenzen
Ein Referenzzyklus (oder Retentionszyklus ) wird so genannt, weil er einen Zyklus in der Objektgrafik angibt:
Jeder Pfeil zeigt an, dass ein Objekt ein anderes behält (starke Referenz). Wenn der Zyklus nicht unterbrochen wird, wird der Speicher für diese Objekte niemals freigegeben .
Ein Haltezyklus wird erstellt, wenn zwei Instanzen von Klassen aufeinander verweisen:
class A { var b: B? = nil }
class B { var a: A? = nil }
let a = A()
let b = B()
a.b = b // a retains b
b.a = a // b retains a -- a reference cycle
Bei beiden Instanzen bleiben sie bis zum Ende des Programms erhalten. Dies ist ein Haltezyklus.
Schwache Referenzen
Um unowned
zu vermeiden, verwenden unowned
beim Erstellen von Referenzen das Schlüsselwort weak
oder nicht unowned
, um die unowned
.
class B { weak var a: A? = nil }
Schwache oder nicht besetzte Referenzen erhöhen die Referenzanzahl einer Instanz nicht. Diese Referenzen tragen nicht dazu bei, Zyklen einzuhalten. Die schwache Referenz wird zu nil
wenn das Objekt, auf das sie verweist, freigegeben wird.
a.b = b // a retains b
b.a = a // b holds a weak reference to a -- not a reference cycle
Wenn Sie mit Verschlüssen arbeiten, können Sie auch weak
und nicht unowned
Capture-Listen verwenden .
Manuelle Speicherverwaltung
Wenn Sie mit C-APIs arbeiten, möchten Sie möglicherweise den Referenzzähler von Swift deaktivieren. Dies wird mit nicht verwalteten Objekten erreicht.
Wenn Sie einen Typ-punned Zeiger auf eine C - Funktion zu liefern, verwenden toOpaque
Verfahren der Unmanaged
Struktur einen Rohzeiger zu erhalten, und fromOpaque
die ursprüngliche Instanz zu erholen:
setupDisplayLink() {
let pointerToSelf: UnsafeRawPointer = Unmanaged.passUnretained(self).toOpaque()
CVDisplayLinkSetOutputCallback(self.displayLink, self.redraw, pointerToSelf)
}
func redraw(pointerToSelf: UnsafeRawPointer, /* args omitted */) {
let recoveredSelf = Unmanaged<Self>.fromOpaque(pointerToSelf).takeUnretainedValue()
recoveredSelf.doRedraw()
}
Beachten Sie, dass Sie bei Verwendung von passUnretained
und Gegenstücken alle Vorsichtsmaßnahmen wie bei unowned
Referenzen unowned
.
Um mit älteren Objective-C-APIs zu interagieren, sollte der Referenzzähler eines bestimmten Objekts manuell beeinflusst werden. Für das Unmanaged
entsprechende Methoden retain
und release
. Nichtsdestotrotz ist es wünschenswert, passRetained
und takeRetainedValue
, die die takeRetainedValue
durchführen, bevor das Ergebnis zurückgegeben wird:
func preferredFilenameExtension(for uti: String) -> String! {
let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
guard result != nil else { return nil }
return result!.takeRetainedValue() as String
}
Diese Lösungen sollten immer der letzte Ausweg sein, und sprachnative APIs sollten immer bevorzugt werden.