Swift Language
Geheugen management
Zoeken…
Invoering
Unmanaged
] [1] gebruiken. [1]: https://developer.apple.com/reference/swift/unmanaged
Opmerkingen
Wanneer gebruikt u het zwakke trefwoord:
Hetweak
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:
Hetunowned
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:
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.