Sök…


Introduktion

Detta ämne beskriver hur och när Swift-runtime ska fördela minne för applikationsdatastrukturer och när det minnet ska återvinnas. Som standard hanteras minnesstödsklassens instanser genom referensräkning. Strukturerna överförs alltid genom kopiering. För att välja bort det inbyggda minneshanteringsschemat kan man använda strukturen [ Unmanaged ] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged

Anmärkningar

När du använder det svaga sökordet:

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

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

behålla cykeln

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.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow