Suche…


Einführung

In diesem Thema wird beschrieben, wie und wann die Swift-Laufzeit Speicher für Anwendungsdatenstrukturen reservieren soll und wann dieser Speicher freigegeben werden soll. Standardmäßig werden die Instanzen der Speichersicherungsklasse durch Referenzzählung verwaltet. Die Strukturen werden immer kopiert. Um das integrierte Speicherverwaltungsschema abzulehnen, kann die Struktur [ Unmanaged ] [1] verwendet werden. [1]: https://developer.apple.com/reference/swift/unmanaged

Bemerkungen

Wann das schwache Schlüsselwort verwendet wird:

Das weak 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:

Das unowned -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:

Zyklus beibehalten

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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow