Swift Language
Minneshantering
Sök…
Introduktion
Unmanaged
] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged
Anmärkningar
När du använder det svaga sökordet:
Detweak
nyckelordet bör användas om ett referensföremål kan omlokaliseras under objektets livstid för referensen. När man ska använda det obesedda nyckelordet:
Detunowned
nyckelordet bör användas om ett refererat objekt inte förväntas omfördelas under objektets livstid för referensen. Fallgropar gropar~~POS=HEADCOMP
Ett vanligt fel är att glömma att skapa referenser till objekt som krävs för att leva vidare efter att en funktion har avslutats, som platschefer, rörelsehanterare etc.Exempel:
class A : CLLocationManagerDelegate
{
init()
{
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Det här exemplet fungerar inte ordentligt eftersom platshanteraren är omplacerad efter att initialiseraren återvänder. Den rätta lösningen är att skapa en stark referens som en instansvariabel:
class A : CLLocationManagerDelegate
{
let locationManager:CLLocationManager
init()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Referenscykler och svaga referenser
En referenscykel (eller behållningscykel ) heter så att den indikerar en cykel i objektgrafen :
Varje pil anger ett objekt som behåller ett annat (en stark referens). Om inte cykeln bryts, kommer minnet för dessa objekt aldrig att frigöras .
En behållningscykel skapas när två instanser av klasser refererar till varandra:
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
Båda fallen kommer de att leva på tills programmet avslutas. Detta är en behållningscykel.
Svaga referenser
För att undvika behållningscykler använder du nyckelordet weak
eller unowned
när du skapar referenser för att bryta behållningscykler.
class B { weak var a: A? = nil }
Svaga eller okända referenser kommer inte att öka referensräkningen för en instans. Dessa referenser bidrar inte till att behålla cykler. Den svaga referensen blir nil
när objektet som den refererar är omlokaliserat.
a.b = b // a retains b
b.a = a // b holds a weak reference to a -- not a reference cycle
När du arbetar med stängningar kan du också använda weak
och unowned
i fångstlistor .
Manuell minnehantering
När man gränsar till C API: er kan man kanske backa upp Swift-referensräknaren. Att göra det uppnås med obemanade objekt.
Om du behöver tillhandahålla en typpunnad pekare till en C-funktion, använd toOpaque
metoden i den Unmanaged
strukturen för att få en rå pekare och fromOpaque
att återställa den ursprungliga instansen:
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()
}
Observera att om du använder passUnretained
och motsvarigheter, är det nödvändigt att vidta alla försiktighetsåtgärder som med unowned
referenser.
För att interagera med äldre Objekt-C API: er, kanske man vill påverka referensräkningen för ett visst objekt manuellt. För att Unmanaged
har respektive metoder retain
och release
. Ändå är det mer önskvärt att använda passRetained
och takeRetainedValue
, som utför behållning innan resultatet returneras:
func preferredFilenameExtension(for uti: String) -> String! {
let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
guard result != nil else { return nil }
return result!.takeRetainedValue() as String
}
Dessa lösningar bör alltid vara den sista utväg, och språk-ursprungliga API: er måste alltid föredras.