Zoeken…


Invoering

In dit onderwerp wordt beschreven hoe en wanneer de Swift-runtime geheugen moet toewijzen voor toepassingsdatastructuren en wanneer dat geheugen moet worden teruggewonnen. Standaard worden de exemplaren van de geheugenback-upklasse beheerd door referentietelling. De structuren worden altijd doorgevoerd door te kopiëren. Als u zich wilt afmelden voor het ingebouwde geheugenbeheerschema, kunt u de structuur [ Unmanaged ] [1] gebruiken. [1]: https://developer.apple.com/reference/swift/unmanaged

Opmerkingen

Wanneer gebruikt u het zwakke trefwoord:

Het weak sleutelwoord moet worden gebruikt als een object waarnaar wordt verwezen tijdens de levensduur van het object dat de referentie bevat, kan worden toegewezen.

Wanneer gebruikt u het sleutelwoord niet-eigendom:

Het unowned sleutelwoord moet worden gebruikt als verwacht wordt dat een object waarnaar wordt verwezen niet wordt toegewezen tijdens de levensduur van het object dat de referentie bevat.

valkuilen

Een veel voorkomende fout is om te vergeten verwijzingen naar objecten te maken, die nodig zijn om van te leven nadat een functie is beëindigd, zoals locatiemanagers, bewegingsmanagers, enz.

Voorbeeld:

class A : CLLocationManagerDelegate
{
    init()
    {
        let locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.startLocationUpdates()
    }
}

Dit voorbeeld zal niet goed werken, omdat de locatiemanager wordt toegewezen nadat de initialisatie terugkeert. De juiste oplossing is om een sterke referentie te maken als instantievariabele:

class A : CLLocationManagerDelegate
{
    let locationManager:CLLocationManager

    init()
    {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.startLocationUpdates()
    }
}

Referentiecycli en zwakke referenties

Een referentiecyclus (of cyclus behouden ) wordt zo genoemd omdat deze een cyclus in de objectgrafiek aangeeft:

cyclus behouden

Elke pijl geeft het ene object aan dat een ander vasthoudt (een sterke referentie). Tenzij de cyclus wordt verbroken, zal de herinnering aan deze objecten nooit worden vrijgemaakt .

Een vasthoudcyclus wordt gemaakt wanneer twee instanties van klassen naar elkaar verwijzen:

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

Beide instanties zullen leven totdat het programma eindigt. Dit is een vasthoudcyclus.

Zwakke referenties

Om het behoud van cycli te voorkomen, gebruikt u het sleutelwoord weak of unowned bij het maken van referenties om het behoud van cycli te onderbreken.

class B { weak var a: A? = nil }

Zwakke of niet-bezeten referenties zullen het aantal referenties van een instantie niet verhogen. Deze referenties dragen niet bij aan het behouden van cycli. De zwakke referentie wordt nil wanneer het object waarnaar wordt verwezen, wordt toegewezen.

a.b = b  // a retains b
b.a = a  // b holds a weak reference to a -- not a reference cycle

Wanneer u met sluitingen werkt, kunt u ook weak en unowned in opnamelijsten gebruiken .

Handmatig geheugenbeheer

Wanneer u interfacet met C API's, wilt u misschien de Swift-referentieteller terugdringen. Dit wordt bereikt met onbeheerde objecten.

Als u een type-punn pointer aan een C-functie moet leveren, gebruikt toOpaque methode toOpaque van de Unmanaged structuur om een onbewerkte pointer te verkrijgen en fromOpaque om de oorspronkelijke instantie te herstellen:

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()
}

Merk op dat als u passUnretained en tegenhangers gebruikt, het noodzakelijk is om alle voorzorgsmaatregelen te nemen, net als bij unowned referenties.

Om te communiceren met legacy Objective-C API's, zou je de referentietelling van een bepaald object handmatig willen kunnen beïnvloeden. Daarvoor heeft Unmanaged respectieve methoden retain en release . Het is echter meer wenselijk om passRetained en takeRetainedValue , die behouden behouden voordat het resultaat wordt takeRetainedValue :

func preferredFilenameExtension(for uti: String) -> String! {
  let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
  guard result != nil else { return nil }

  return result!.takeRetainedValue() as String
}

Deze oplossingen moeten altijd het laatste redmiddel zijn en API's met een eigen taal hebben altijd de voorkeur.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow