Swift Language
Zarządzanie pamięcią
Szukaj…
Wprowadzenie
Unmanaged
] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged
Uwagi
Kiedy stosować słowo kluczowe słaby:
weak
słowo kluczowe powinno być użyte, jeśli obiekt, do którego istnieje odwołanie, może zostać cofnięty w czasie życia obiektu zawierającego odwołanie. Kiedy używać słowa kluczowego „unowned”:
unowned
należy użyć, jeśli nie oczekuje się, że odwołany obiekt zostanie cofnięty w czasie istnienia obiektu zawierającego odwołanie. Pułapki
Częstym błędem jest zapominanie o tworzeniu odniesień do obiektów, które muszą żyć po zakończeniu funkcji, takich jak menedżery lokalizacji, menedżery ruchu itp.Przykład:
class A : CLLocationManagerDelegate
{
init()
{
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Ten przykład nie działa poprawnie, ponieważ menedżer lokalizacji jest zwalniany po powrocie inicjalizatora. Właściwym rozwiązaniem jest utworzenie silnego odwołania jako zmiennej instancji:
class A : CLLocationManagerDelegate
{
let locationManager:CLLocationManager
init()
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.startLocationUpdates()
}
}
Cykle referencyjne i słabe referencje
Cykl odniesienia (lub cykl zachowania ) jest tak nazwany, ponieważ wskazuje cykl na wykresie obiektowym :
Każda strzałka wskazuje, że jeden obiekt zachowuje drugi (silne odniesienie). Jeśli cykl nie zostanie przerwany, pamięć dla tych obiektów nigdy nie zostanie uwolniona .
Cykl przechowywania jest tworzony, gdy dwa wystąpienia klas odwołują się do siebie:
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
Oba wystąpienia będą trwać do momentu zakończenia programu. To jest cykl przechowywania.
Słabe referencje
Aby uniknąć cykli zatrzymania, użyj słowa kluczowego weak
lub unowned
podczas tworzenia odwołań, aby przerwać cykle zatrzymania.
class B { weak var a: A? = nil }
Słabe lub nieznane referencje nie zwiększą liczby referencji instancji. Te odniesienia nie przyczyniają się do zachowania cykli. Słabe odniesienie staje się nil
gdy obiekt, do którego się odwołuje, zostaje zwolniony.
a.b = b // a retains b
b.a = a // b holds a weak reference to a -- not a reference cycle
Podczas pracy z zamknięciami możesz także używać weak
i unowned
na listach przechwytywania .
Ręczne zarządzanie pamięcią
Podczas współpracy z interfejsami API języka C można chcieć wycofać licznik referencji Swift. Można to zrobić w przypadku niezarządzanych obiektów.
Jeśli musisz podać wskaźnik z oznaczeniem typu do funkcji C, użyj metody toOpaque
struktury Unmanaged
, aby uzyskać surowy wskaźnik, i fromOpaque
aby odzyskać oryginalną instancję:
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()
}
Pamiętaj, że jeśli używasz passUnretained
i odpowiedników, passUnretained
zachować wszelkie środki ostrożności, jak w przypadku unowned
referencji.
Aby współdziałać ze starszymi interfejsami API Objective-C, można ręcznie wpłynąć na liczbę odwołań do określonego obiektu. W tym celu Unmanaged
ma odpowiednie metody retain
i release
. Niemniej jednak bardziej pożądane jest użycie passRetained
i takeRetainedValue
, które wykonują zachowanie przed zwróceniem wyniku:
func preferredFilenameExtension(for uti: String) -> String! {
let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
guard result != nil else { return nil }
return result!.takeRetainedValue() as String
}
Rozwiązania te powinny zawsze być ostatecznością, a interfejsy API dla języków powinny być zawsze preferowane.